前面我们分享了一段双均线策略的核心代码,并简单的完善了一下(QMT入门——非常简洁的双均线策略、QMT入门——非常简洁的双均线策略 2、QMT入门——非常简洁的双均线策略 3),今天做最后的完善:
1、由之前的固定的两支股池升级为5支股池,这5只股票来源于沪深300成份股,每天选择沪深300成份股中存货周转率最高的5支作为股池。由于存货周转率数据一般随财报公布,实际上股池每个季度更新一次。
2、获取行情函数,由get_history_data升级为get_market_data_ex,后者运行速度更快。
3、遇到股池更新时,将不在股池中的持仓股立即卖出,按新股池中的股票运行策略。
注意:这个策略不可用于实盘,只能用来跑回测。因为它太简陋了,就算用来模拟都不行,更不用说是实盘,举个例子来说,回测数据中,买入时间都是15:00:00,卖出时间都是00:00:00,这在实际中根本不可能。
更新后的代码如下:
#encoding:gbkimport numpy as npimport datetimeimport pandas as pd"""示例说明:双均线实盘策略,通过计算快慢双均线,在金叉时买入,死叉时做卖出"""class a(): passA = a() #创建空的类的实例 用来保存委托状态 def init(C): A.acct= '666' #随便设置一个账号 A.acct_type= 'STOCK' #账号类型 A.amount = 10000 #单笔买入金额 触发买入信号后买入指定金额 A.line1=17 #快线周期 A.line2=27 #慢线周期 A.buy_code = 23 if A.acct_type == 'STOCK' else 33 #买卖代码 区分股票 与 两融账号 A.sell_code = 24 if A.acct_type == 'STOCK' else 34 print(f'双均线实盘示例{A.acct} {A.acct_type} 单笔买入金额{A.amount}')def handlebar(C): #选股 A.stock = C.get_stock_list_in_sector('沪深300') index = 0 df = pd.DataFrame(columns=['代码','存货周转率']) for sto in A.stock: inv_tur = C.get_financial_data('PERSHAREINDEX', 'inventory_turnover', sto[-2:], sto[:6], C.barpos) index += 1 # 追加的新行数据 new_row = {'代码': sto, '存货周转率': inv_tur} # 追加行 df.loc[len(df)] = new_row df = df.sort_values(by=['存货周转率'], ascending=False) A.stock = df['代码'][:5].tolist() print('选出股票:',A.stock) account = get_trade_detail_data(A.acct, A.acct_type, 'account') if len(account)==0: print(f'账号{A.acct} 未登录 请检查') return account = account[0] available_cash = int(account.m_dAvailable) #获取持仓数据,后续买入和卖出股票都要用到持仓数据 holdings = get_trade_detail_data(A.acct, A.acct_type, 'position') holdings = {i.m_strInstrumentID + '.' + i.m_strExchangeID : i.m_nCanUseVolume for i in holdings} #获取行情数据 data = C.get_market_data_ex(['close'],A.stock, end_time=timetag_to_datetime(C.get_bar_timetag(C.barpos),'%Y%m%d'),period = "1d",count = max(A.line1, A.line2)+1) for hs in holdings: if hs not in A.stock: msg = f"{timetag_to_datetime(C.get_bar_timetag(C.barpos),'%Y%m%d')} 双均线实盘 换股" passorder(A.sell_code, 1101, A.acct, hs, 14, -1, holdings[hs], '双均线实盘', 1 , msg, C) print('换股!') for s in A.stock: close_list = data[s]['close'] #行情数据不足将停止运行后面的代码 if len(close_list) < max(A.line1, A.line2)+1: print('行情长度不足(新上市或最近有停牌) 跳过运行') return #以下四行在计算金叉死叉时要用到 pre_line1 = np.mean(close_list[-A.line1-1: -1]) pre_line2 = np.mean(close_list[-A.line2-1: -1]) current_line1 = np.mean(close_list[-A.line1:]) current_line2 = np.mean(close_list[-A.line2:]) #如果快线穿过慢线,则买入委托 当前无持仓 买入 vol = int(A.amount / close_list[-1] / 100) * 100 #买入数量 向下取整到100的整数倍 if A.amount < available_cash and vol >= 100 and s not in holdings and pre_line1 < pre_line2 and current_line1 > current_line2: #下单开仓 ,参数说明可搜索PY交易函数 passorder msg = f"{timetag_to_datetime(C.get_bar_timetag(C.barpos),'%Y%m%d')} 双均线实盘 {s} 上穿均线 买入 {vol}股" passorder(A.buy_code, 1101, A.acct, s, 14, -1, vol, '双均线实盘', 1 , msg, C) print(msg) #如果快线下穿慢线,则卖出委托 if s in holdings and holdings[s] > 0 and pre_line1 > pre_line2 and current_line1 < current_line2: msg = f"{timetag_to_datetime(C.get_bar_timetag(C.barpos),'%Y%m%d')} 双均线实盘 {s} 下穿均线 卖出 {holdings[s]}股" passorder(A.sell_code, 1101, A.acct, s, 14, -1, holdings[s], '双均线实盘', 1 , msg, C) print(msg) #查询委托和成交情况 orders = get_trade_detail_data(A.acct, A.acct_type, 'order') for o in orders: avg_price = o.m_dTradeAmount/o.m_nVolumeTraded bors = '买入' if o.m_nOffsetFlag==48 else '卖出' print(f' 委托和成交情况:\n 股票代码: {o.m_strInstrumentID}.{o.m_strExchangeID},\n 买卖方向: {bors},\n 委托数量: {o.m_nVolumeTotalOriginal},\n' f' 成交均价: {avg_price:.3f},\n 成交数量: {o.m_nVolumeTraded},\n 成交金额:{o.m_dTradeAmount:.2f}') pos = get_trade_detail_data(A.acct, A.acct_type, 'position') print(f'{timetag_to_datetime(C.get_bar_timetag(C.barpos),"%Y%m%d")}\n 持仓情况:') mkv=0 if len(pos): for p in pos: print(f' 股票代码:{p.m_strInstrumentID}.{p.m_strExchangeID},\n 剩余数量:{p.m_nVolume},\n 持仓成本:{p.m_dOpenPrice:.3f},\n 盈亏比例:{p.m_dProfitRate:.2%}') mkv += p.m_dMarketValue else: print(' 空仓') acco = get_trade_detail_data(A.acct, A.acct_type, 'account')#POSITION_STATISTICS #position_statistics for ac in acco: print(f'{timetag_to_datetime(C.get_bar_timetag(C.barpos),"%Y%m%d")}\n 账户统计:') print(f' 总资产:{ac.m_dBalance:.2f},\n 可用现金:{ac.m_dAvailable:.2f},\n 总市值:{mkv:.2f},\n 账户盈亏:{ac.m_dPositionProfit:.2%}')
返回(中段部分截图):

一些知识点讲解一下:
26行,返回沪深300指数成份股。
28行,创建只有列名的空dataframe。
29-36行,生成一个dataframe,有两列,分别为代码和存货周转率,按存货周转率降序排列。
38、39行,截取dataframe前5行,并转换为只有代码的列表。
51-55行,遇到股池更新时,将不在股池中的持仓股立即卖出。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/73401
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!