前面我们分享了一段双均线策略的核心代码,并简单的完善了一下(QMT入门——非常简洁的双均线策略、QMT入门——非常简洁的双均线策略 2),今天再添加以下细节:
1、将交易的股票数量增加至多只(本次以2支演示)。
2、增加了每日的持仓情况。
3、增加了每日的账户情况。
更新后的代码如下:
#encoding:gbk
import numpy as np
import datetime
"""
示例说明:双均线实盘策略,通过计算快慢双均线,在金叉时买入,死叉时做卖出
"""
class a():
pass
A = a() #创建空的类的实例 用来保存委托状态
def init(C):
A.stock= ['000002.SZ','002049.SZ'] #交易品种
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
#设置股票池 订阅品种行情
C.set_universe(A.stock)
print(f'双均线实盘示例{A.stock} {A.acct} {A.acct_type} 单笔买入金额{A.amount}')
def handlebar(C):
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_history_data(max(A.line1, A.line2)+1, '1d', 'close',dividend_type='none')
for s in A.stock:
close_list = data[s]
#行情数据不足将停止运行后面的代码
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')
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%}')
返回(中段部分截图):

现在每个回测的交易日都有持仓情况和账户统计,如发生交易,会显示委托和成交情况。
一些知识点讲解一下:
第14行,多只股票用列表、元组或集合的形式赋值都可以,回测都能正常运行。
第38行,用for循环实现对第14行的每一只股票进行判断和交易。
第69行,用get_trade_detail_data(A.acct, A.acct_type, ‘position’)函数来获取整体持仓情况。
第71、76行,用来计算账户总市值。我用get_trade_detail_data(A.acct, A.acct_type, ‘account’)取出来的总市值总是0,不知道是什么原因,于是,只好用最原始的方式——将每只股票的市值求和。
第74行,用for循环来提取每一支股票的持仓情况。
第79行,用get_trade_detail_data(A.acct, A.acct_type, ‘account’)函数来获取账户情况。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/73402
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!