这几天把回测代码改成了实盘,发现还是有几个区别的。同样的策略,聚宽选出来的股票和QMT选出来的股票存在较大的差异,5只里面有4只不一样。由于对QMT的回测功能和数据质量存疑。干脆用聚宽的模拟盘将信号写入云数据库,然后QMT只负责读取选股结果。
1.如果你采用handle_bar 的形式,那么需要加上下面的代码
#跳过历史k线
if not C.is_last_bar():
return
如果不加这段代码,那么就算是实盘,他会从历史K线开始运行。
2.实盘可以通过如下代码设置账号
g.acct = account
ContextInfo.set_account(g.acct)
g.acct_type = accountType
3.当天卖出的股票,如果查询holdings,还是可以查到,只是他的可用股数为零,所以需要用如下代码查询
g.holdings = {i.m_strInstrumentID + '.' + i.m_strExchangeID : i.m_nCanUseVolume for i in holdings if i.m_nCanUseVolume > 0}
特别注意加上 if i.m_nCanUseVolume > 0
4.由于在实盘中,从委托到成交需要一定的时间,所以我会选择卖出一些股票后,隔一段时间再去买股票,当然这种做法非常粗糙。例如下面的代码。
ContextInfo.run_time('trade_sell', '1nDay', '2013-12-25 13:05:00')
ContextInfo.run_time('trade_buy', '1nDay', '2013-12-25 13:10:00')
这里我用了run_time(),而不是handle_bar()。
最后附上一段仅用来下单的实盘代码。如果有问题欢迎联系我
#coding:gbk
"""
轻量级仅下单实盘策略
"""
from sqlalchemy import create_engine
import sqlalchemy
import pandas as pd
import numpy as np
from datetime import datetime
class A():
pass
g = A() #创建空的类的实例 用来保存委托状态
def init(ContextInfo):
g.acct = account
ContextInfo.set_account(g.acct)
g.acct_type = accountType
g.buy_code = 23
g.sell_code = 24
g.buy_stock_count = 5
g.strat_name = '成长小市值RSRS-MV择时'
g.engine_ = create_engine("mysql+pymysql://改成你的用户名:密码@Ip地址:端口/数据库名?charset=utf8")
ContextInfo.run_time('trade_sell', '1nDay', '2013-12-25 13:05:00')
ContextInfo.run_time('trade_buy', '1nDay', '2013-12-25 13:10:00')
def trade_sell(ContextInfo):
now_time = datetime.now()
account = get_trade_detail_data(g.acct, g.acct_type, 'account')
if len(account)==0:
print(f'账号{g.acct} 未登录 请检查')
return
holdings = get_trade_detail_data(g.acct, g.acct_type, 'position')
g.holdings = {i.m_strInstrumentID + '.' + i.m_strExchangeID : i.m_nCanUseVolume for i in holdings if i.m_nCanUseVolume > 0}
sql = """
select code_list from stocks_list;
"""
df = pd.read_sql_query(sql, g.engine_)
rsrs_stocks = df['code_list'].iloc[-1]
rsrs = rsrs_stocks.split(';')[0]
stock_list = rsrs_stocks.split(';')[1:]
stock_list = [code_transfer(stock) for stock in stock_list]
g.stock_list = stock_list
g.rsrs = rsrs
print(now_time, rsrs)
if rsrs == 'SELL':
if len(g.holdings) > 0:
print(now_time, 'RSRS SELL, 全部卖出')
for s in g.holdings.keys():
if not ContextInfo.is_suspended_stock(s):
msg = f"RSRS小市值实盘 {s} 卖出 {g.holdings[s]}股"
# 按对手价立即下单
passorder(g.sell_code, 1101, g.acct, s, 14, -1, g.holdings[s], g.strat_name,2, msg, ContextInfo)
return
else:
# 先卖出不在名单中的股票
stocks_to_sell = [s for s in g.holdings.keys() if s not in stock_list]
for s in stocks_to_sell:
msg = f"RSRS小市值实盘 {s} 卖出 {g.holdings[s]}股"
print(now_time, msg)
if not ContextInfo.is_suspended_stock(s):
passorder(g.sell_code, 1101, g.acct, s, 14, -1,g.holdings[s], g.strat_name, 2, msg, ContextInfo)
def trade_buy(ContextInfo):
if g.rsrs == 'SELL':
return
# 买入股票
now_time = datetime.now()
holdings = get_trade_detail_data(g.acct, g.acct_type, 'position')
g.holdings = {i.m_strInstrumentID + '.' + i.m_strExchangeID : i.m_nCanUseVolume for i in holdings if i.m_nCanUseVolume > 0}
print('可用资金', get_total_value(g.acct,'STOCK'))
stocks_to_buy = []
num_stocks_to_buy = g.buy_stock_count - len(g.holdings)
for s in g.stock_list:
if s not in g.holdings.keys():
stocks_to_buy.append(s)
if len(stocks_to_buy) >= num_stocks_to_buy:
break
if len(stocks_to_buy) > 0:
value = get_total_value(g.acct,'STOCK') / len(stocks_to_buy)
for s in stocks_to_buy: # 立即以最新价格下单
latest_price = ContextInfo.get_market_data_ex(['close'], \
[s],period='1m', count = 1)[s]['close'][0]
vol = value // (latest_price *100 * 1.01) # * 1.01 防止钱不够
msg = f"RSRS小市值 {s} 买入 {vol * 100}股"
print(now_time, msg)
# 按对手价下单
passorder(g.buy_code, 1101, g.acct, s, 14, -1, vol*100, g.strat_name, 2, msg, ContextInfo)
else:
print(now_time, '无需换仓')
def get_total_value(account_id,datatype):#(账号,账户类型)
'''
获取账户当前可用现金
'''
result = 0
result_list = get_trade_detail_data(account_id,datatype,'ACCOUNT')
for obj in result_list:
result = obj.m_dAvailable
return result
def code_transfer(stock_code):
if stock_code.endswith('.XSHG'):
stock_code = stock_code.replace('XSHG', 'SH')
else:
stock_code = stock_code.replace('XSHE', 'SZ')
return stock_code