实盘量化QMT踩坑记录(四)


这几天把回测代码改成了实盘,发现还是有几个区别的。同样的策略,聚宽选出来的股票和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