均线:对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些平均值连起来,成为一条线,就叫做N日移动平均线。移动平均线常用线有5日、10日、30日、60日、120日的指标。
5日和10日的是短线操作参照指标,称作日均线指标;
30日和60日的是中期均线指标,称作季均线指标;
120日和240日的是长期均线指标,称作年均线指标。
金叉:短期均线上穿长期均线,买入信号。
死叉:短期均线下穿长期均线,卖出信号。
交易策略:金叉买入,死叉卖出。
二、金叉死叉交易练习1、使用tushare包获取某股票的历史行情import numpy as npimport pandas as pdimport matplotlib.pyplot as plt# Python绘图和数据可视化的工具包import tushare as tsts.get_k_data("601318", start="2004-01-30").to_csv('601318.csv')df = pd.read_csv('601318.csv', index_col="date", parse_dates=['date'])[['open', 'close', 'high', 'low']]print(df)"""open closehigh lowdate2007-03-0121.25419.89021.66619.4692007-03-0219.97919.72820.16619.503...... ... ... ...2020-01-2285.00085.22085.48083.8302020-01-2384.01083.49084.56082.480[3076 rows x 4 columns]"""2、使用pandas包计算该股票历史数据的5日和30均线5日均线则前4天没有均线,30日均线则前29天没有均线。
(1)普通方法df['ma5'] = np.nan # 创建5日均值列df['ma30'] = np.nan# 创建30日均值列print(df)"""open closehigh lowma5ma30date 2007-03-0121.25419.89021.66619.469NaN NaN2007-03-0219.97919.72820.16619.503NaN NaN...... ... ... ...... ...2020-01-2285.00085.22085.48083.830NaN NaN2020-01-2384.01083.49084.56082.480NaN NaN"""for i in range(4, len(df)):# 从第五个到最后一个# 当天和前四天的收盘价的平均值为5日均线值df.loc[df.index[i], 'ma5'] = df["close"][i-4:i+1].mean() # i=4是第五天,[0,5]print(df)"""open closehigh lowma5ma30date 2007-03-0121.25419.89021.66619.469NaN NaN2007-03-0219.97919.72820.16619.503NaN NaN2007-03-0519.54518.86519.62618.504NaN NaN2007-03-0618.70419.23519.55418.597NaN NaN2007-03-0719.25219.75819.93619.09019.4952 NaN...... ... ... ...... ...2020-01-2384.01083.49084.56082.48085.6320 NaN"""for i in range(29, len(df)):# 从第30个到最后一个# 当天和前29天的收盘价的平均值为30日均线值df.loc[df.index[i], 'ma30'] = df["close"][i-29:i+1].mean()print(df)"""open closehigh lowma5 ma30date2007-03-0121.25419.89021.66619.469NaNNaN2007-03-0219.97919.72820.16619.503NaNNaN2007-03-0519.54518.86519.62618.504NaNNaN2007-03-0618.70419.23519.55418.597NaNNaN2007-03-0719.25219.75819.93619.09019.4952NaN...... ... ... .........2020-01-1786.15086.25086.90085.85086.178085.2923332020-01-2088.30087.60088.70087.35086.408085.3876672020-01-2187.00085.60087.29085.60086.162085.4526672020-01-2285.00085.22085.48083.83086.044085.5070002020-01-2384.01083.49084.56082.48085.632085.488667"""(2)简单方法df['ma5'] = df['close'].rolling(5).mean()df['ma30'] = df['close'].rolling(30).mean()print(df)"""open closehigh lowma5 ma30date2007-03-0121.25419.89021.66619.469NaNNaN2007-03-0219.97919.72820.16619.503NaNNaN2007-03-0519.54518.86519.62618.504NaNNaN2007-03-0618.70419.23519.55418.597NaNNaN2007-03-0719.25219.75819.93619.09019.4952NaN...... ... ... .........2020-01-1786.15086.25086.90085.85086.178085.2923332020-01-2088.30087.60088.70087.35086.408085.3876672020-01-2187.00085.60087.29085.60086.162085.4526672020-01-2285.00085.22085.48083.83086.044085.5070002020-01-2384.01083.49084.56082.48085.632085.488667"""3、使用matplotlib包可视化历史数据的收盘价和两条均线df[['close', 'ma5', 'ma30']].plot()plt.show()运行后显示效果:
4、分析输出所有金叉日期和死叉日期如果前一交易日五日均线小于30日均线,后一交易日五日均线大于30日均线,则说明是金叉;
如果前一交易日五日均线大于30日均线,后一交易日五日均线小于30日均线,则说明是死叉。
(1)循环的解法# dropna()删除含有空数据的全部行,axis参数可删除含义空数据的全部列df = df.dropna()gloden_cross = []# 金叉death_cross = []# 死叉for i in range(0, len(df)-1):if df['ma5'][i] >= df['ma30'][i] and df['ma5'][i-1] = df['ma30'][i-1]:death_cross.append(df.index[i])print('金叉日期', gloden_cross)"""金叉日期 [Timestamp('2007-06-14 00:00:00'), Timestamp('2007-12-10 00:00:00'),..., Timestamp('2020-01-02 00:00:00')]"""print('死叉日期', death_cross)"""死叉日期 [Timestamp('2007-06-04 00:00:00'), Timestamp('2007-11-06 00:00:00'),..., Timestamp('2019-12-23 00:00:00')]"""(2)简便算法# dropna()删除含有空数据的全部行,axis参数可删除含义空数据的全部列df = df.dropna()sr1 = df['ma5'] < df['ma30']sr2 = df['ma5'] >= df['ma30']death_cross = df[sr1 & sr2.shift(1)].indexgolden_cross = df[-(sr1 | sr2.shift(1))].indexprint('金叉日期', golden_cross)"""金叉日期 DatetimeIndex(['2007-04-12', '2007-06-14', '2007-12-10', '2008-04-23',..., '2020-01-02']"""print('死叉日期', death_cross)"""死叉日期 DatetimeIndex(['2007-06-04', '2007-11-06', '2007-12-13', '2008-05-20',..., '2019-11-12', '2019-12-23']"""5、使用该策略的炒股收益率如果我从2010年1月1日起,初始资金为100000元,金叉尽量买入,死叉全部卖出,则到今天为止,我的炒股收益率?
# 炒股收益率first_money = 100000money = first_money# 持有的资金hold = 0 # 持有的股票sr1 = pd.Series(1, index=golden_cross)sr2 = pd.Series(0, index=death_cross)sr = sr1.append(sr2).sort_index()# 将两个表合并,并按时间排序sr = sr['2010-01-01':] # 从2010年1月1日开始for i in range(0, len(sr)):p = df['open'][sr.index[i]]# 当天的开盘价if sr.iloc[i] == 1:# 金叉buy = money // (100 * p) # 买多少手hold += buy * 100money -= buy * 100 * pelse:# 死叉money += hold * phold = 0# 持有股票重置为0# 计算最后一天股票市值加上持有的资金p = df['open'][-1]now_money = hold * p + moneyprint('当前持有资产总额:', now_money)print('盈亏情况:', now_money - first_money)"""当前持有资产总额: 551977.7999999997盈亏情况: 451977.7999999997"""需要注意的是:这里金叉死叉都是按照当天的收盘价计算的。但是如果得到当天的收盘价就已经无法进行交易了。因此要让策略可行,需要按照当天的开盘价计算。
三、在JoinQuant(聚宽)平台实现双均线策略金叉:若5日均线大于10日均线且不持仓死叉:若5日均线小于10日均线且持仓
1、策略实现# 导入函数库from jqdata import *# 初始化函数,设定基准等等def initialize(context):# 设定沪深300作为基准set_benchmark('000300.XSHG')# 开启动态复权模式(真实价格)set_option('use_real_price', True)# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')g.security = ["601318.XSHG"]g.p1 = 5# 五日均线g.p2 = 10 # 十日均线def handle_data(context, data):# 遍历股票for stock in g.security:df = attribute_history(stock, g.p2)# 十日均线的值ma10 = df['close'].mean()# 五日均线的值ma5 = df['close'][-5:].mean()if ma10 > ma5 and stock in context.portfolio.positions: # 具有持仓# 死叉卖出order_target(stock, 0)if ma10 < ma5 and stock not in context.portfolio.positions:# 不具有持仓# 金叉买入# order(stock, context.portfolio.available_cash) # 能买多少买多少order(stock, context.portfolio.available_cash * 0.8) # 可用资金的80%买入
执行效果:
2、record函数——画图函数
调用record函数可用来描画额外的曲线。
参数:一个或多个key=value形式的参数,key为曲线名称,value为值。
在双均线策略中加入画图函数:
# 导入函数库from jqdata import *# 初始化函数,设定基准等等def initialize(context):# 设定沪深300作为基准set_benchmark('000300.XSHG')# 开启动态复权模式(真实价格)set_option('use_real_price', True)# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')g.security = ["601318.XSHG"]g.p1 = 5# 五日均线g.p2 = 10 # 十日均线def handle_data(context, data):# 遍历股票for stock in g.security:df = attribute_history(stock, g.p2)# 十日均线的值ma10 = df['close'].mean()# 五日均线的值ma5 = df['close'][-5:].mean()if ma10 > ma5 and stock in context.portfolio.positions: # 具有持仓# 死叉卖出order_target(stock, 0)if ma10 < ma5 and stock not in context.portfolio.positions:# 不具有持仓# 金叉买入# order(stock, context.portfolio.available_cash) # 能买多少买多少order(stock, context.portfolio.available_cash * 0.8) # 可用资金的80%买入record(ma5=ma5, ma10=ma10)执行显示如下: