一个简单的 指数增强python模型示例。
<font color=red size=12>可回测,可实盘。</font>
基于原迅投QMT示例程序改编,原示例模型已老旧,不可运行。
其它参考请点击以下链接:
【分享】小白入门的迅投QMT股票模型开发上手指南(腾讯文档)
https://www.xuntou.net/forum.php?mod=viewthread&tid=1844&user_code=PN4WZC
来自: 迅投QMT社区
【源码】一个最简单的MACD红绿柱翻转买卖的策略
https://www.xuntou.net/forum.php?mod=viewthread&tid=405&user_code=PN4WZC
来自: 迅投QMT社区
#coding:gbk
'''
指数增强型策略
以 沪深300 为股票池
1、先选出指数权重 0.0015 -- 0.003 之间的股票
2、价格在 5.00 -- 30.00 之间
3、价格大于均线 20
选出的结果大约 20支左右,订阅这些品种。
然后计算交易权重,
连续3天上涨,并成交量也上涨,m30上价格在 均线20以上。为 1.0
连续2天上涨,并成交量也上涨,m30上价格在 均线20以下。为 0.8
连续2天上涨,并成交量下降,m30上价格在 均线20以上。为 0.6
日线图,价格在 均线20之下,为 0
以 100万为总资金,持仓金额为 100万 * 指数权重 * 交易权重
运行在 m30图表上,根据金额调仓。
'''
#在指数(例如HS300)日线下运行
import numpy as np
import pandas as pd
class G(): pass
g = G()
g.Stock300 = [] # 沪深 300 的成份股
g.StockList = [] # 订阅的股票
g.DayData = {}
g.M30Data = {}
g.StockPos = {}
g.StockRatio = {} # 品种的权重
def init(ContextInfo):
print("\n此程序基于指数增强策略改编")
print("code by 智能交易*姚")
print("请提前下载好历史数据,包括1分钟K线数据!")
print("回测时请选择 默认品种为 000300,默认周期为 30分钟")
print("程序默认以 100万(1000000.00) 为 初始资金")
if ContextInfo.period != '30m':
print("K线图表的默认周期 请选择 30分钟")
return
#设置股票池
g.Stock300 = ContextInfo.get_stock_list_in_sector('沪深300')
g.DayData = ContextInfo.get_market_data_ex(
['close','volume'], # 获取 收盘 和 成交额
g.Stock300, # 获取的品种是 000300.SH
period = '1d', # 获取 日K线的 周期
start_time = '', # 开始时间 缺省
end_time = '', # 结束时间 缺省
count = -1, # 从最右边的一根K线开始,获取 10 根K线的数据
dividend_type='none', # 复权方式以主图表的方式为准
subscribe=False # 订阅数据
)
g.M30Data = ContextInfo.get_market_data_ex(
['close','volume'], # 获取 收盘 和 成交额
g.Stock300, # 获取的品种是 000300.SH
period = '30m', # 获取 30m线的 周期
start_time = '', # 开始时间 缺省
end_time = '', # 结束时间 缺省
count = -1, # 从最右边的一根K线开始,获取 10 根K线的数据
dividend_type='none', # 复权方式以主图表的方式为准
subscribe=False # 订阅数据
)
for symbol in g.Stock300:
# 筛选股票
# 保留权重大于0.35%的成份股。结果保存在字典 ContextInfo.stock300_weight中,如 '000725.SZ':0.006909999
SymbolRatio = ContextInfo.get_weight_in_index("000300.SH", symbol) / 100
MA20 = g.DayData[symbol]['close'].rolling(window=20).mean()
g.StockRatio[symbol] = 0.0
if (g.DayData[symbol]['close'].iloc[-1] < 30.00 and # 价格小于 30
g.DayData[symbol]['close'].iloc[-1] > 5.00 and # 价格大于 5
g.DayData[symbol]['close'].iloc[-1] > MA20.iloc[-1] and # 价格大于 均线20
SymbolRatio > 0.0015 and # 权重大于 0.015
SymbolRatio < 0.0030 # 权重小于 0.003
):
g.StockList.append(symbol)
g.StockRatio[symbol] = SymbolRatio
# print("品种",symbol,"昨收盘价:",g.DayData[symbol]['close'].iloc[-1],"权重", SymbolRatio)
print("选出成份股 ",len(g.StockList),"合计支。包括 ",g.StockList)
print('所占权重总和为: ', round(sum(g.StockRatio.values()),2),)
ContextInfo.set_account("testS")
def handlebar(ContextInfo):
AccountID = "testS"
money = 0
UseMoney = 100000.00
Symbol = ""
trader_vol = 0
StockRatio = {}
NewPrice = 0.0 # 获取 最新价格
timetag_1 = ContextInfo.get_bar_timetag(ContextInfo.barpos)
timetag_2 = ContextInfo.get_bar_timetag(ContextInfo.barpos+1)
timetag_3 = ContextInfo.get_bar_timetag(ContextInfo.barpos+2)
timetag_4 = ContextInfo.get_bar_timetag(ContextInfo.barpos+3)
bar_1stime = timetag_to_datetime(timetag_1, '%Y%m%d%H%M%S')
bar_2stime = timetag_to_datetime(timetag_2, '%Y%m%d%H%M%S')
bar_3stime = timetag_to_datetime(timetag_3, '%Y%m%d%H%M%S')
bar_4stime = timetag_to_datetime(timetag_4, '%Y%m%d%H%M%S')
g.Stock300 = ContextInfo.get_stock_list_in_sector('沪深300')
for s in g.Stock300:
g.StockPos[s] = {"持股总数量":0,
"可用数量":0,
"盈亏比例":0,
"持仓成本":0
}
if str(bar_1stime[-6:-1]) == "093000":
for s in g.Stock300:
g.StockPos[s] = {"今日交易次数":0}
account_list = get_trade_detail_data(AccountID,'stock','account')
for acc in account_list:
money = acc.m_dAvailable # 帐户可用资金
# UseMoney = acc.m_dBalance
PosList = get_trade_detail_data(AccountID,'stock','position')
for pos in PosList:
Symbol = pos.m_strInstrumentID + "." + pos.m_strExchangeID # 组合成 600025。SH 这样的字符串
g.StockList.append(Symbol)
if Symbol not in g.Stock300:
continue
g.StockPos[Symbol]["持股总数量"] = pos.m_nVolume
g.StockPos[Symbol]["可用数量"] = pos.m_nCanUseVolume
g.StockPos[Symbol]["盈亏比例"] = pos.m_dProfitRate
g.StockPos[Symbol]["持仓成本"] = pos.m_dPositionCost
if g.StockPos[Symbol]["盈亏比例"] < - 0.03: # 止损
# print("亏损达到:",round(pos.m_dProfitRate,2),"全部卖出!")
passorder(24, 1101, AccountID, Symbol, 5, 0, pos.m_nCanUseVolume, "止损卖出",1,"1", ContextInfo)
g.StockPos[Symbol]["今日交易次数"] = 1
# print("-----------------------")
if g.StockPos[Symbol]["盈亏比例"] > 0.1: # 止盈
# print("浮盈达到:",round(pos.m_dProfitRate,2),"全部卖出!")
passorder(24, 1101, AccountID, Symbol, 5, 0, pos.m_nCanUseVolume, "止盈卖出",1,"1", ContextInfo)
g.StockPos[Symbol]["今日交易次数"] = 1
# print("-----------------------")
# ------------------开始回测程序---------------------------------------
if ContextInfo.do_back_test:
# print("\n 开始回测模式......")
if int(bar_1stime) > 20230318000000 and int(bar_1stime) < 20240101000000:
PosList = get_trade_detail_data(AccountID,'stock','position')
for pos in PosList:
Symbol = pos.m_strInstrumentID + "." + pos.m_strExchangeID # 组合成 600025。SH 这样的字符串
passorder(24, 1101, AccountID, Symbol, 5, 0, pos.m_nVolume, "卖出",1,"1", ContextInfo)
return
g.StockList = []
for symbol in g.Stock300:
# 筛选股票
# 保留权重大于0.35%的成份股。结果保存在字典 ContextInfo.stock300_weight中,如 '000725.SZ':0.006909999
SymbolRatio = ContextInfo.get_weight_in_index("000300.SH", symbol) / 100
dayMA20 = g.DayData[symbol]['close'].rolling(window=20).mean()
if (g.DayData[symbol]['close'].iloc[-1] < 30.00 and # 价格小于 30
g.DayData[symbol]['close'].iloc[-1] > 5.00 and # 价格大于 30
g.DayData[symbol]['close'].iloc[-1] > dayMA20.iloc[-1] and # 价格大于 均线20
SymbolRatio > 0.0015 and # 权重大于 0.015
SymbolRatio < 0.0030 # 权重小于 0.003
):
g.StockList.append(symbol)
g.StockRatio[symbol] = SymbolRatio
# print("品种",symbol,"昨收盘价:",g.DayData[symbol]['close'].iloc[-1],"权重", SymbolRatio)
for symbol in g.StockList:
dayMA20 = g.DayData[symbol]['close'].rolling(window=20).mean()
m30MA20 = g.M30Data[symbol]['close'].rolling(window=20).mean()
day1_index = g.DayData[symbol]['close'].index.get_loc(bar_1stime[0:8])
day2_index = day1_index -1
day3_index = day1_index -2
day4_index = day1_index -3
if ( g.DayData[symbol]['close'].iloc[day3_index] < g.DayData[symbol]['close'].iloc[day2_index] and # 前2天的收盘价都上涨
g.DayData[symbol]['close'].iloc[day4_index] < g.DayData[symbol]['close'].iloc[day3_index] and
g.DayData[symbol]['volume'].iloc[day3_index] < g.DayData[symbol]['volume'].iloc[day2_index] and # 成交量也上涨
g.M30Data[symbol]['close'].loc[bar_1stime] > m30MA20.loc[bar_1stime] # m30 价格在 均线 20之上
):
StockRatio[symbol] = 1.0
if ( g.DayData[symbol]['close'].iloc[day3_index] < g.DayData[symbol]['close'].iloc[day2_index] and # 前2天的收盘价都上涨
g.DayData[symbol]['volume'].iloc[day3_index] < g.DayData[symbol]['volume'].iloc[day2_index] and # 成交量也上涨
g.M30Data[symbol]['close'].loc[bar_1stime] < m30MA20.loc[bar_1stime] # m30 价格在 均线 20之下
):
StockRatio[symbol] = 0.8
if ( g.DayData[symbol]['close'].iloc[day3_index] < g.DayData[symbol]['close'].iloc[day2_index] and # 前2天的收盘价都上涨
g.DayData[symbol]['volume'].iloc[day3_index] > g.DayData[symbol]['volume'].iloc[day2_index] and # 成交量下降
g.M30Data[symbol]['close'].loc[bar_1stime] > m30MA20.loc[bar_1stime] # m30 价格在 均线 20之上
):
StockRatio[symbol] = 0.6
if ( g.DayData[symbol]['close'].iloc[day2_index] < dayMA20.iloc[day2_index]):
StockRatio[symbol] = 0.0
#------------------准备调仓交易
for symbol in g.Stock300:
if symbol not in StockRatio: continue
money = UseMoney * g.StockRatio[symbol] *100 * StockRatio[symbol]
NewPrice = g.M30Data[symbol].loc[bar_2stime,"close"] # 获取 最新价格
# print("品种 ",symbol,"交易权重为 ",StockRatio[symbol],"指数权重为:",g.StockRatio[symbol])
# print("应持仓金额为: ",money)
if money < 0.01 and g.StockPos[symbol]["可用数量"] >= 100: # 如果要求持仓为0,但有持仓,则卖出
#print("品种 ",symbol,"应持仓金额为 ",money,"全出!")
passorder(24, 1101, AccountID, symbol, 5, 0, g.StockPos[symbol]["可用数量"], "调仓卖出",1,"1", ContextInfo)
#print("------------------------------------")
if money > 0.01 :
order_target_value(symbol, money, ContextInfo,AccountID)
#print("品种 ",symbol,"调整持仓金额为 ",round(money,2))
#print("------------------------------------")
return # 回测结束
# ----------------------------------------------------------------------------------------
if not ContextInfo.is_last_bar(): # 这不是最右边的那根K线上的跳价?
return # 那就返回,退出程序
#-------------------刷新数据-----------------------------------------------
m30Data = ContextInfo.get_market_data_ex(
['close','volume'],
g.Stock300,
period = '30m',
count = 1,
dividend_type='none', # 复权方式以主图表的方式为准
subscribe = True
)
for Symbol in g.Stock300:
g30mD_stime = g.M30Data[Symbol].index.tolist() # 获取 初始化时 的时间戳
m30D_stime = m30Data[Symbol].index.tolist() # 获取 新5m 的时间戳
if len(m30D_stime) > 0: # 确实获取到了新的报价数据
if m30D_stime[0] not in g30mD_stime : # 30m 更新了一根 K 线
g.M30Data[Symbol] = pd.concat([g.M30Data[Symbol],m30Data[Symbol]])
# print("品种",Symbol,"30分K线图表上出现一根新的K线,已加入到全局数据对象 g.m30Data 中。")
g.M30Data[Symbol].loc[m30D_stime[0]] = m30Data[Symbol].loc[m30D_stime[0]] # 直接刷新一行数据
NewPrice = m30Data[Symbol]["close"].iloc[-1] # 获取 最新价格
dayMA20 = g.DayData[Symbol]['close'].rolling(window=20).mean()
m30MA20 = g.M30Data[Symbol]['close'].rolling(window=20).mean()
day1_index = g.DayData[Symbol]['close'].index.get_loc(bar_1stime[0:8])
day2_index = day1_index -1
day3_index = day1_index -2
day4_index = day1_index -3
if ( g.DayData[Symbol]['close'].iloc[day3_index] < g.DayData[Symbol]['close'].iloc[day2_index] and # 前2天的收盘价都上涨
g.DayData[Symbol]['close'].iloc[day4_index] < g.DayData[Symbol]['close'].iloc[day3_index] and
g.DayData[Symbol]['volume'].iloc[day3_index] < g.DayData[Symbol]['volume'].iloc[day2_index] and # 成交量也上涨
g.M30Data[Symbol]['close'].loc[bar_1stime] > m30MA20.loc[bar_1stime] # m30 价格在 均线 20之上
):
StockRatio[Symbol] = 1.0
if ( g.DayData[Symbol]['close'].iloc[day3_index] < g.DayData[Symbol]['close'].iloc[day2_index] and # 前2天的收盘价都上涨
g.DayData[Symbol]['volume'].iloc[day3_index] < g.DayData[Symbol]['volume'].iloc[day2_index] and # 成交量也上涨
g.M30Data[Symbol]['close'].loc[bar_1stime] < m30MA20.loc[bar_1stime] # m30 价格在 均线 20之下
):
StockRatio[Symbol] = 0.8
if ( g.DayData[Symbol]['close'].iloc[day3_index] < g.DayData[Symbol]['close'].iloc[day2_index] and # 前2天的收盘价都上涨
g.DayData[Symbol]['volume'].iloc[day3_index] > g.DayData[Symbol]['volume'].iloc[day2_index] and # 成交量下降
g.M30Data[Symbol]['close'].loc[bar_1stime] > m30MA20.loc[bar_1stime] # m30 价格在 均线 20之上
):
StockRatio[Symbol] = 0.6
if ( g.DayData[Symbol]['close'].iloc[day2_index] < dayMA20.iloc[day2_index]):
StockRatio[Symbol] = 0.0
#------------------准备调仓交易
for Symbol in g.Stock300:
if Symbol not in StockRatio: continue
money = UseMoney * g.StockRatio[Symbol] *100 * StockRatio[Symbol]
# print("品种 ",symbol,"交易权重为 ",StockRatio[symbol],"指数权重为:",g.StockRatio[symbol])
# print("应持仓金额为: ",money)
if money < 0.01 and g.StockPos[Symbol]["可用数量"] >= 100: # 如果要求持仓为0,但有持仓,则卖出
#print("品种 ",Symbol,"应持仓金额为 ",money,"全出!")
passorder(24, 1101, AccountID, Symbol, 5, 0, g.StockPos[Symbol]["可用数量"], "调仓卖出",1,"1", ContextInfo)
#print("------------------------------------")
if money > 0.01 :
money = money - g.StockPos[Symbol]["持仓成本"] # 应持有金额 与 现持有金额的差值
trader_vol = (money / NewPrice) //100 * 100
trader_vol = abs(trader_vol)
if money < 0: # 应减仓
passorder(24,1101,AccountID,Symbol,5,0,trader_vol,"减仓卖出",1,"1",ContextInfo)
print("品种 ",Symbol,"调整持仓金额为 ",round(money,2),"实际持仓金额为:",g.StockPos[Symbol]["持仓成本"],"减仓卖出")
elif money > 0: # 应加仓
passorder(23,1101,AccountID,Symbol,5,0,trader_vol,"加仓买入",1,"1",ContextInfo)
print("品种 ",Symbol,"调整持仓金额为 ",round(money,2),"实际持仓金额为:",g.StockPos[Symbol]["持仓成本"],"加仓卖入")
#print("------------------------------------")
print("==========================================")
return