如何写策略

从一个最简单策略开始

下面先从一个最简单策略开始,这个策略中,若发现没有仓位就开仓下单,有仓位就平仓。下单都用market市场单。

from qedata import *
from qereal import *
from datetime import timedelta
import pandas as pd
import numpy as np
import talib
from talib import MA_Type
class mystrat(qeStratBase):
# 策略必须从qeStratBase继承派生
    def __init__(self):
        self.instid = ['AG2112.SFE'] ## 合约名是必填项
        self.holding_flag = False    # 是否有仓位的标识

    def handleData(self,context):
        try:    
            if context.curtime.second == 10:# 若当前时间秒数为10,防止过多开平仓
                if not self.holding_flag: #如果现在账户中没有仓位,就买入
                    make_order(context, instid=context.instid[0], direction=1, price=10000,\
                           volume=1,ordertype='market',action='open')  
                    self.holding_flag = True #现在账户下有仓位
                else: #如果现在账户中有仓位,就卖出
                    make_order(context, instid=context.instid[0],direction=-1, price=10000, \
                       volume=1, ordertype='market',action='close',closetype='closetoday')
                    self.holding_flag = False #现在账户下仓位被清完
        except Exception as e:
            print('handleData error', e.__traceback__.tb_lineno, e)

    def crossDay(sellf, context):
        ##撤掉所有未成交订单
        cancel_order(context, 0)

这里可以看到一个宽易平台的策略需要从qeStratBase派生类,并且具有如下类函数成员:

  • __init__构造函数

    这里用于策略初始化,可以在这里设定策略自定义参数以及初始值。这里instid这个参数为必填项,需要写明策略的合约名列表。

  • handleData 处理行情数据

    本策略是tick级策略,每次新行情到来自动回调该策略函数。

  • crossDay 处理切换交易日

    这里主要是处理跨交易日,通过该函数对订单以及其他变量做处理以适应交易日变化

这三个函数都使用 context 作为参数,该参数是系统数据接口,策略可以通过该接口访问关键的当前系统数据,包括并不限于

  • 当前日期时间
  • 当前数据切片
  • 当前订单表
  • 当前成交表
  • 当前持仓信息
  • 当前盈亏回撤等统计数据
  • 各种关键参数

另外,策略还访问了两个主要的系统函数接口:

  • 下单函数 make_order

    可以下开仓/平仓单,可以做多/做空,各种下单需求统一到一个接口函数

  • 撤单函数 cancel_order

    可以根据orderid订单编号撤单,订单号由make_order返回值给出。若orderid参数设置为0,可以自动清除所有未成交订单。

以上系统数据接口和函数接口的详细参考说明见 系统接口说明

布林带单合约策略

下面使用布林带技术指标实现一个低频日线的真正交易策略, 当价格超过布林带上轨时候做空,超过下轨做多。策略主体代码如下:

from qedata import *
from qereal import *

#写布林带策略
class mystrat(qeStratBase):
    def __init__(self):
        self.flippage = 1 ##设置模拟撮合交易市价单产生的滑点数
        self.traderate = 0.2 ##设置交易手数占市场交易量最大比例
        self.instid = ['AG2112.SFE'] ## 合约名是必填项
        self.name = 'Bollinger' ## 给策略取名
        self.datamode = 'daily' ## 日线bar策略
        self.dailyminutes = 5 ## 收盘提前5分钟产生日线bar

    def onBar(self, context):
        ## 获取当前日期
        curday = context.curtime.date()
        instid = self.instid[0]
        try:
            ## 获取开始时间到昨天的所有历史行情
            df1 = get_price(instid, start_date, curday-timedelta(days=1), 'daily')
            ## 获取当天收盘前的日bar数据
            df2 = context.getDailyData(instid)
            ## 拼接成一个DataFrame
            df = pd.concat([df1,df2],join='outer')
            ## 计算布林带上下轨
            close = df.close.values
            upper,middle,lower=talib.BBANDS(close,timeperiod=5, matype=MA_Type.T3)
            if not np.isnan(upper[-1]):
                 ## 若布林带数据非空
                if close[-1] < lower[-1]:
                    ##低于下轨,做多
                    make_order(context, instid, 1, close[-1], 1,'market',action='open')
                elif close[-1] > upper[-1]:
                    ##高于上轨,做空
                    make_order(context, instid,-1, close[-1], 1,'market',action='open')
                if close[-1] > middle[-1] and context.getAccountPosition(instid,'long','volume') > 0:
                    ##有多仓回到中轨以上,平多
                    make_order(context,  instid,-1, close[-1],context.getAccountPosition(instid,'long','volume'),\
                               'market',action='close',closetype='closetoday')
                if close[-1] < middle[-1] and context.getAccountPosition(instid,'short','volume') > 0:    
                    ##有空仓回到中轨一下,平空
                    make_order(context, instid,1, close[-1], context.getAccountPosition(instid,'short','volume'),\
                               'market',action='close',closetype='closetoday')

        except Exception as e:
            print('handleData error', e.__traceback__.tb_lineno, e)

    def crossDay(sellf, context):
        ##撤掉所有未成交订单
        cancel_order(context, 0)

该策略相比第一个策略,使用了技术指标作为交易信号,更加贴近真实策略,当然真正策略远比这个复杂,除了交易信号,还得考虑仓位管理和风控。另一方面,这个策略中__init__函数作为类构造函数并且初始化了两个参数:

  • datamode

    str类型。仅支持 'daily', 'minute', 'tick' 三种,即为日线bar, 分钟bar和tick级数据频率模式。默认为‘tick’, 回调函数为handleData, 若为其他类型,回调函数为onBar。

  • dailyminutes

    int类型。 默认为5, 代表收盘前5分钟平台会回调onBar函数。用户可以修改这个数值。当策略的instid合约列表中不同合约收盘时间不同时,以最早的那个为准。

  • flippage

    int 类型。默认为0. 该参数用于回测或者模拟中撮合成交时对于市价单设定的滑点数,以尽可能模拟真实交易情况。若不设置,默认为0.

    注: 实盘中该参数无效。

  • traderate

    float 类型。默认为1。该参数为用户策略初始化时赋值, 用于回测或者模拟中撮合成交时允许 成交量占当前市场成交量的最大比例,比如self.traderate=0.2表示成交时成交量最大允许占当前市场时间段成交量的20%,超过将不予成交。

    注: 实盘中该参数无效

其他需要在策略初始化函数中配置的参数,我们将在后续策略参数表中详述。

我们将在后续如何回测章节中给出该策略完整的回测过程以及评估回测效果。

注:日线或分钟线策略在实盘中也会收到handleData的tick级回报,可以用于处理成交回报等及时性比较强的操作

bar分钟级数据策略

在模拟盘和实盘中我们某些中长线策略使用分钟级以上数据即可,或者是对均线采样以及蜡烛图有计算要求。下面以一个例子来说明此类策略如何处理。

class mystrat(qeStratBase):
# 策略必须从qeStratBase继承派生
    def __init__ (self):
        self.holding_flag = False    # 是否有仓位的标识
        self.instid = ['AG2206.SFE'] ##合约名列表为必填项
        self.datamode = 'minute'
        self.freq = 1
        self.wait_all = False


    def onBar(self,context):
        try:
            res=get_bar(context,freq=5,count=None) #获取bar数据
            if not self.holding_flag: #如果现在账户中没有仓位,就买入
                make_order(context, instid=context.instid[0], direction=1, price=10000,\
                           volume=1,ordertype='market',action='open')  
                self.holding_flag = True #现在账户下有仓位
            else: #如果现在账户中有仓位,就卖出
                make_order(context, instid=context.instid[0],direction=-1, price=10000, \
                           volume=1, ordertype='market',action='close',closetype='closetoday')
                self.holding_flag = False #现在账户下仓位被清完
        except Exception as e:
            print('onBar error', e.__traceback__.tb_lineno, e)

    def crossDay(sellf, context):
        ##撤掉所有未成交订单
        cancel_order(context, 0)

以上处理和tick级策略不同之处如下:

  • 需要设置策略的三个参数:datamode, freq 和 wait_all, 说明如下:

    • 参数说明
      参数
      参数 类型 说明 默认值
      datamode str 数据类型, 有效值为'tick'分笔数据,'minute'分钟级,'daily'日级.该值为'tick'系统调用策略的handleData函数,否则调用onBar函数。 ‘tick’
      freq int 当datamode为‘minute’时该参数有效,该参数决定多长时间会调用一次onBar函数,范围1-60,3表示3分钟一次 0
      wait_all str 若为True,等所有合约都有新分钟数据触发onBar, 否则只要任一合约到达新分钟都会触发。datamode不为‘minute’或者freq为0时无效。 False
  • 在onBar函数而不是handleData 函数处理行情数据

  • 可以通过get_bar函数获得今日开盘后所有分钟级bar行情数据(也可以是数分钟),也可以将该数据与历史行情(get_price函数)拼接得到想要的多日bar数据。获得bar数据的函数和字段说明如 get_bar说明

    注意:

    1. 策略中的freq 是int类型,代表多少分钟调用一次onBar。不能写成'60T'之类字符串。
    2. get_bar函数中的freq参数决定获取bar数据的采样评率,该参数可以与策略中的freq不同,比如strat.freq=1可以1分钟调用一次onBar函数,然后用get_bar(context, 5)获取五分钟采样频率的数据。
    3. 回测模式下当策略freq为1的时候, get_bar函数的freq参数是有效的,可以决定数据采样频率,但若策略freq不为1, 那么get_bar函数的freq无效,只能返回和策略freq一样采样频率的数据。
    4. ‘daily’方式在模拟和实盘模式下不可使用, 只能用‘minute’模式去模拟,也就是自己合成日线bar,在临近收盘时判断是否交易。

商品对冲多合约策略

以上都是单合约回测,若涉及多合约对冲策略,相对要复杂一些。

首先我们需要一个formula公式,来描述对冲的比例和相关关系。如果没有formula对冲公式,那么宽易平台就会当做多合约非对冲策略处理。该公式作为策略成员变量在策略构造函数中初始化。比如下文策略, 该策略根据远月价格除以近月价格的比值作为指标,根据该数据 动态的布林线计算上轨,下轨和中轨。当超过上轨做空比价,超过下轨做多比价来获利。

此策略为分钟级bar策略

##对冲策略设计
class hedgeStrat(qeStratBase):
    def __init__(self):
        self.instid =['AG2112.SFE','AG2206.SFE']
        self.datamode = 'minute' ## 分钟级策略
        self.freq = 1 # 每一分钟收到一次onBar
        self.formula = 'b/a' ##计算公式为log(合约2/合约1),用比价代替
        self.name = 'hedge AG' ##策略名
        ##保存仓位数据
        self.pos0 = {'long':0,'short':0} 
        self.pos1 = {'long':0,'short':0}
        self.longvol = 0
        self.shortvol = 0
        ##最大持仓手数
        self.maxvol = 50
    def onBar(self,context):
        try:
            ##比较context仓位和本地仓位,若不符合,则判断还在等待交易未成交
            bTrading = (self.pos0['long'] != context.getAccountPosition(context.instid[0],'long','volume')) or \
                       (self.pos0['short'] != context.getAccountPosition(context.instid[0],'short','volume')) or \
                       (self.pos1['long'] != context.getAccountPosition(context.instid[1],'long','volume')) or \
                       (self.pos1['short'] != context.getAccountPosition(context.instid[1],'short','volume')) 


            #若非等待交易有方差数据
            if not bTrading : 
                    bardata = get_bar(context, 1) # 获取当天bar数据
                    curday = context.curtime.date() # 获取当天日期
                    offset = 1 if curday.weekday() > 0 else 3  ## 若为周一 往前3天, 否则往前1天
                    ## 获取第一个合约前一个交易日数据
                    df1 = get_price(context.instid[0],curday-timedelta(days=offset), curday,'minute')
                    while len(df1) == 0: ## 处理万一有节假日情况,找到最近一个工作日
                        offset += 1
                        df1 = get_price(context.instid[0],curday-timedelta(days=offset), curday,'minute')
                    ## 获取第二个合约前一个交易日数据
                    df2 = get_price(context.instid[1],curday-timedelta(days=offset), curday,'minute')

                    ## 将数据和当天bar数据拼接
                    df1 = pd.concat([df1,bardata[context.instid[0]]],join='outer')
                    df2 = pd.concat([df2,bardata[context.instid[1]]],join='outer')

                    ## 获得两个合约价格的log差
                    close1 = df1.close.values
                    close2 = df2.close.values
                    close = np.log(close2)-np.log(close1)

                    ## 使用布林带计算log比价的上轨,中轨,下轨
                    upper,middle,lower=talib.BBANDS(close,timeperiod=15, matype=MA_Type.T3)

                    if  close[-1] < lower[-1] and self.longvol + self.shortvol < self.maxvol :
                    #低于下轨并且还没到最大仓位,做多价差
                        self.pos0['short'] += 1
                        self.pos1['long'] += 1
                        self.longvol += 1
                        ##合约0下空单
                        make_order(context,context.instid[0],-1,\
                                                   context.getCurrent(context.instid[0]),1,'market',action='open')
                        ##合约1下多单
                        make_order(context,context.instid[1],1, \
                                      context.getCurrent(context.instid[1]),1,'market',action='open')
                        ##记录当前对冲开仓点
                        record_hedge_point(context,'open','short',1)

                    elif close[-1] > upper[-1] and self.longvol + self.shortvol < self.maxvol:
                    #高于上轨并且还没到最大仓位,做多价差
                        self.pos0['long'] += 1
                        self.pos1['short'] += 1
                        self.shortvol += 1
                        #合约0下多单
                        make_order(context,context.instid[0],1, \
                                      context.getCurrent(context.instid[0]),1,'market',action='open')
                        #合约1下空单
                        make_order(context,context.instid[1],-1, \
                                      context.getCurrent(context.instid[1]),1,'market',action='open')
                        #记录当前对冲开仓点
                        record_hedge_point(context,'open','long',1)

                    if close[-1] > middle[-1] and self.longvol > 0:
                     #高于中轨并且有多头仓位,平仓
                        #合约0平空仓
                        make_order(context,context.instid[0],1, \
                                      context.getCurrent(context.instid[0]),self.longvol,\
                                   'market',action='close',closetype='closetoday')
                        #合约1平多仓
                        make_order(context,context.instid[1],-1, \
                                      context.getCurrent(context.instid[1]),self.longvol,\
                                   'market',action='close',closetype='closetoday')
                        #记录当前对冲平仓点
                        record_hedge_point(context,'close','short',1)
                        self.pos0['short'] = 0
                        self.pos1['long'] = 0
                        self.longvol = 0

                    if close[-1] < middle[-1] and self.shortvol > 0:
                      #低于中轨并且有空头仓位,平仓
                        #合约0平多仓
                        make_order(context,context.instid[0],-1, \
                                      context.getCurrent(context.instid[0]),self.shortvol,\
                                   'market',action='close',closetype='closetoday')
                        #合约1平空仓
                        make_order(context,context.instid[1],1, \
                                      context.getCurrent(context.instid[1]),self.shortvol,\
                                   'market',action='close',closetype='closetoday')
                        #记录当前对冲平仓点
                        record_hedge_point(context,'close','long',1)
                        self.pos0['long'] = 0
                        self.pos1['short'] = 0
                        self.shortvol = 0
        except Exception as e:
            print('handleData error', e.__traceback__.tb_lineno, e)

我们可以发现,对冲策略与普通策略有两点不同:

  1. 在策略构造函数里增加了对冲公式 formula='b/a'
  2. 使用record_hedge_point记录对冲开平仓信息

接下来让我们来了解一下这两个部分:

self.formula 对冲公式:

字符串类型。 默认值为None

在策略类开头,使用formula=' '定义对冲公式,formula为字符串形式。例如: 钢厂利润= 1 螺纹钢期货价格- 1.6 铁矿石期货价格+0.5 焦炭期货价格. 此时formula='1 a - 1.6 b - 0.5 c'。

在上面的策略中, formula='b/a' ,若a为'AG2206.SFE',b为'AG2112.SFE', 那么在策略中判断交易信号不是按照任一合约的价格,而是按照'AG2206.SFE'的价格除以'RB2205.SFE'的价格的比率数据来作为交易信号。

record_hedge_point 对冲点记录函数:

在真实 的对冲交易中,往往存在两个品种之间的流动性差异,为了尽量减少滑点,实际对冲交易往往先用限价单挂单流动性比较差的单个合约,若成交才会用市价单交易另一个流动性比较好的合约。这就造成了不同合约交易时间点不同的问题。而画图和监控最好可以看得出在哪个数值上进行的开平仓。所以需要额外设计一个函数来手动记录对冲交易点,包括开仓和平仓。

函数的详细说明参见: 对冲点记录函数说明

若策略没有在构造函数中设置self.formula 或者 self.formula为None 时,该函数无效。

策略参数表

策略参数表详细如下,除了instid必须设置以外,其他参数若不设置,会自动采用默认值。

参数说明
参数
参数 类型 说明 默认值
instid list 合约名列表,比如['AG2206.SFE'],该参数必须在策略构造函数中给出合法合约列表 None
datamode str 数据类型, 有效值为'tick'分笔数据,'minute'分钟级,'daily'日级.该值为'tick'系统调用策略的handleData函数,否则调用onBar函数。 ‘tick’
freq int 当datamode为‘minute’时该参数有效,bar数据的分钟采样频率,范围1-60,3表示3分钟采样一次 0
wait_all str 若为True,等所有合约都有新分钟数据触发onBar, 否则只要任一合约到达新分钟都会触发。datamode不为‘minute’或者freq为0时无效。 False
flippage int 在回测或模拟交易中市价订单订单撮合时候的的滑点tick数,实盘无效。 0
traderate float 用于回测或者模拟中撮合限价单成交时允许 成交量占当前市场成交量的最大比例,比如self.traderate=0.2表示成交时成交量最大允许占当前市场时间段成交量的20%,超过将不予成交.实盘无效 1.0
formula str 对冲公式比如'b/a',为None代表不是对冲模式,用于对冲策略中,此时对于成交结果将按照该公式计算值来显示开平仓图。 None
name str 用户自定义策略名,若不设置系统将自动给策略命名为比如“stg0”, 自定义名不要使用该格式,避免和系统命名冲突。 None
rfrate float 计算sharp比率等指标时使用的无风险利率 0.02

系统数据接口context

context接口用于策略访问环境和交易的关键数据。

合约列表

context.instid

list类型。 该参数为回测、模拟、实盘接口函数的必备入参,在这里存入系统数据接口context,方便策略代码随时引用。

示例

print(context.instid)

返回值

['RB2205.SFE','AG2206.SFE']

运行模式

context.runmode

str类型。'test'代表在回测模式, ‘simu’ 代表模拟测试模式, ‘real’ 代表实盘模式。用于分别做一些处理。

示例

print(context.runmode)

返回值

'test'

函数说明

参数表

*
参数 类型 回测 模拟 实盘 说明 备注
user str 系统登录用户名,可以通过getuserid函数获取.
runmode str 'test'回测,'simu'模拟,'real'实盘,一个参数切换运行模式.
strat qeStratBase / list qeStratBase派生策略或派生策略的列表,回测只支持单策略,输入列表仅第一项有效,模拟/实盘支持多策略并发
simu_token str 模拟用令牌token。使用createSimuAccount创建的模拟账户时生成。
mode_724 bool 是否使用SIMNOW 7x24小时模拟测试服务.默认False不使用,不使用时非市场开盘时间不可以运行模拟或实盘交易。若为True使用,但需要客户给出SIMNOW账户信息。
csv_orders bool 是否使用csv下单工具.默认False不使用,True为使用,不可用于回测,详见 辅助工具相关说明。
simu_simnow724_account dict 模拟用SIMNOW7*24小时账户信息,当模拟测试时 mode_724为True时,系统将检查该项账户配置,比如{'investorid':'133231','password':’888888'}
real_account dict 实盘交易使用的账户信息。若mode_724为True,该实盘账户应设置为SIMNOW7*24小时账户。详见实盘交易
printlog bool 是否打印开平仓信息和warning信息。默认为True
rfrate float 无风险利率,用于计算sharp比率等,默认2%
test_dynamic_instid bool 是否使用动态合约回测模式,默认为True
test_startdate str 回测数据开始时间,比如'2021-01-01'.test_date不为None,此参数无效
test_enddate str 回测数据结束时间,比如'2021-01-01'.test_date不为None,此参数无效
test_initcap float 回测用初始资金,默认为10000000
test_showchart bool 回测执行结果是否输出三张分析图,默认关闭

返回值

若为模拟/实盘模式,无返回值。若为回测模式,运行结束后返回Dict类型的回测报告。有‘Report’,'Orders','Trades','Cancels'四个Key。

当前数据切片

context.dataslide

dict类型。 以合约名称为key的数据行情切片。回测中,若策略datamode为‘tick’,那么该数据为tick数据, 若为‘minute’,该数据为最新分钟数据。在模拟或者实盘中,该数据始终为最新tick数据。

若为多合约策略,那么该切片为每个合约的最新行情数据,若在该数据时刻某个合约没有更新,那么通过该切片访问的行情是最后一次更新的行情。

若用户在调用回测函数时, 在数据DataFrame入参里面增加里其他自定义字段,也会通过数据切片的方式把当前时间的该添加字段的值反馈给策略。比如客户在‘AG2206.SFE’数据中增加了'variant' 字段, 那么 context.dataslide[‘AG2206.SFE’]['variant'] 就可以访问当前数据时刻的这一字段数值。

键值的默认字段根据不同情况会有不同:

  • ▼ 若为历史行情日线数据
    字段名 类型 描述
    open float 开盘价
    close float 收盘价
    high float 最高价
    low float 最低价
    volume int 成交量
    money float 成交额
    upperlimit float 涨停价
    lowerlimit float 跌停价
    position float 持仓量
    presett float 昨结算价
    preclose float 昨收盘价

示例

   print(context.dataslide)

返回值

   {'cu2109.SFE': {'time': Timestamp('2020-10-09 00:00:00'), 'open': 51880.0, 'close': 51620.0, 'high': 51880.0, 'low': 51620.0, 'volume': 4, 'money': 1034050.0, 'position': 32.0, 'upperlimit': 56410.0, 'lowerlimit': 46160.0, 'presett': 51290.0, 'preclose': 51290.0}}
  • ▼ 若为历史行情分钟线数据
    字段名 类型 描述
    open float 开盘价
    close float 收盘价
    high float 最高价
    low float 最低价
    volume int 成交量
    money float 成交额

示例

  print(context.dataslide)

返回值

  {'IC2109.CCF': {'time': Timestamp('2021-07-01 10:13:00'), 'open': 6658.8, 'close': 6652.4, 'high': 6658.8, 'low': 6652.2, 'volume': 34, 'money': 45257480.0}}
  • ▼ 若为历史行情tick数据
    字段名 类型 描述
    current float 最新价
    high float 最高价
    low float 最低价
    volume int 成交量
    money float 成交额
    position float 持仓量
    a1_p float 一档买价
    a1_v int 一档卖量
    b1_p float 一档买价
    b1_v int 一档买量
    tradingday int 交易日,晚盘算下一个交易日

示例

  print(context.dataslide)

返回值

  {'RB2109.sfe': {'time': Timestamp('2021-07-01 09:00:00.500000'), 'current': 5088.0, 'high': 5119.0, 'low': 5080.0, 'volume': 1065, 'money': 54344100.0, 'position': 13334.0, 'a1_p': 5091.0, 'a1_v': 1, 'b1_p': 5082.0, 'b1_v': 13, 'tradingday': 20210701}}
  • ▼ 若为模拟或实盘交易
    字段名 类型 描述
    current float 最新价
    open float 开盘价
    high float 最高价
    low float 最低价
    volume int 成交量
    money float 成交额
    upperlimit float 涨停价
    lowerlimit float 跌停价
    position float 持仓量
    a1_p float 一档买价
    a1_v int 一档卖量
    b1_p float 一档买价
    b1_v int 一档买量
    presett float 昨结算价
    preclose float 昨收盘价

示例

print(context.dataslide)

返回值

{'RB2205.SFE': {'tradingday': '20220406', 'time': '20220406 14:13:30.500', 'timedigit': 20220406141330500, 'current': 5193.0, 'presett': 5137.0, 'preclose': 5189.0, 'open': 5187.0, 'high': 5210.0, 'low': 5111.0, 'volume': 136555, 'money': 7047543130.0, 'position': 455527.0, 'upperlimit': 5650.0, 'lowerlimit': 4623.0, 'b1_p': 5193.0, 'b1_v': 13, 'a1_p': 5194.0, 'a1_v': 24}, 'AG2206.SFE': {'tradingday': '20220406', 'time': '20220406 14:13:30.500', 'timedigit': 20220406141330500, 'current': 4979.0, 'presett': 5047.0, 'preclose': 5038.0, 'open': 4944.0, 'high': 4996.0, 'low': 4913.0, 'volume': 165970, 'money': 12352027905.0, 'position': 438897.0, 'upperlimit': 5551.0, 'lowerlimit': 4542.0, 'b1_p': 4978.0, 'b1_v': 57, 'a1_p': 4979.0, 'a1_v': 5}}

获取最新数据函数

context.getDataSlide(instid, field)

实盘有些非活跃合约可能开盘很长一段时间没有数据,直接用context.dataslide可能会因读不到该instid数据而报错。那么可以使用该函数替代,若当前合约还没有数据,会返回0,避免模拟或实盘中抛出KeyError异常。

▼ 函数说明
参数
参数 类型 说明
instid 字符串 合约名称
feild str 比如"current", 详见context.dataslide字段说明
返回值
若context.dataslide中该合约该字段值存在,则返回该值,否则返回0

示例

print(context.getDataSlide("AU2206.SFE",'current'))

返回值

510.00

获取合约最新价函数

context.getCurrent(instid)

本函数用于获取某合约最新价,若为回测,函数返回‘current’最新价(tick级策略)或者‘close’收盘价(其他采样频率策略);若为模拟或者实盘,该合约有最新价返回最新价,没有返回0, 避免抛出KeyError异常。

▼ 函数说明
参数
参数 类型 说明
instid 字符串 合约名称
返回值
若该账户持仓表中该合约最新价存在,则返回最新价,否则返回0

示例

print(context.getCurrent("AU2206.SFE"))

返回值

510.00

获取账户信息

context.account

当实盘或模拟交易,多策略同时运行,可以通过这个字段查询总账户资金,仓位等。详细字段和说明如下

▼ 账户信息字段名
字段名 类型 说明
context.account.balance float 账户总资金
context.account.avail float 账户总可用权益
context.account.margin float 账户总保证金
context.account.frozenmarg float 账户总冻结保证金
context.account.position dict类型 账户总持仓,详见当前持仓信息表
context.account.orders dict类型 账户订单列表,详见当前委托订单表
context.account.trades dict类型 账户成交列表,详见当前成交列表

示例

print(context.account.balance)

返回值

1012990.00

当前委托订单表

context.account.orders

dict类型。以订单编号orderid 为key的订单表。

▼ 订单字段名
字段名 说明
instid 合约名,比如'AG2001.SFE' 或者'AU9999.SFE'.
price 该委托单的订单的价格
direction 订单方向 1做多 -1做空
ordertype 订单类型 'limit'限价单 'market' 市价单
action 开平类型 'open'开仓/'close'平仓
closetype 平今昨仓类型 'none'开仓订单/'close'平仓/'closeToday'平今/'closeYesterday'平昨
volume 下单量
leftvol 剩余未成交量
cancelvol 撤单量(包含下单失败量)
tradevol 成交量
status 订单状态 'commited'已提交/'failed'失败/'parttraded'部分成交/'alltraded'全部成交/'canceled'已撤/'ptpc'部成部撤
errorid 下单错误编号,成功为0
errormsg 错误信息

注:在CrossDay切换交易日发生的时候,该orders列表会被清空。所以一般来说, 需要在crossDay函数中对订单做处理,以免策略数据与环境数据发生偏差。

示例

oid=31622540002
print(context.account.orders[oid])

返回值

{'instid': 'cu2109.SFE', 'price': 52300.0, 'direction': 1, 'ordertype': 'market', 'closetype': 'none', 'volume': 9, 'leftvol': 9, 'tradevol': 0, 'cancelvol': 0, 'pendvol': 0, 'status': 'committed', 'errorid': 0, 'errormsg': '', 'action': 'open'}

当前成交列表

context.account.trades

dict类型。 以成交编号为key的成交列表。一般来说策略需要在handleData时通过遍历成交编号来找到尚未处理的编号进行处理。

▼ 成交表字段名
字段名 说明
time 成交时间
date 成交日期
action 开仓'open'/平仓'close'
dir 方向 1多 -1空
tradeprice 成交价
vol 成交量
orderid 订单编号
tradeid 成交编号

示例

print(context.account.trades)

返回值

{1: {'time': '00:00:00', 'date': '20201022', 'action': 'open', 'dir': 'long', 'price': 52700.0, 'instid': 'cu2109.SFE', 'tradeprice': 52700.0, 'vol': 1, 'orderid': 1, 'tradeid': 1221114}, 2: {'time': '00:00:00', 'date': '20201022', 'action': 'open', 'dir': 'long', 'price': 52300.0, 'instid': 'cu2109.SFE', 'tradeprice': 52300.0, 'vol': 1, 'orderid': 2, 'tradeid': 1221115}}

当前持仓信息表

context.account.position

dict类型,以合约名为key的持仓列表。

▼ 持仓字段名
字段名 说明
volume 持仓量
poscost 持仓成本
yesvol 昨仓量

示例

print(context.account.position)

返回值

{'CU2109.SFE': {'long': {'poscost': 52700.0, 'volume': 1, 'posProf': 0, 'yesvol': 1}, 'short': {'volume': 0, 'poscost': 0, 'yesvol': 0}}}

注:若会有多策略并行并有重合合约的情况下,请谨慎使用改接口,很可能把别的策略持仓当做本策略进行处理,引起不必要的问题。对于一般情况更建议使用context.getPosition接口来获取本策略仓位

获取账户持仓仓位函数

context.getAccountPosition(instid, direction, field)

本函数用于获取总账户某合约的仓位信息。尤其当多策略并行时,可以查到账户的该合约的总仓位,而不是当前策略的合约仓位。若当前合约尚且不存在于context.account.position中,该函数返回0,避免抛出KeyError异常。相对于直接调用context.account.position,改函数避免了调用前先判断Key是否存在的麻烦。

▼ 函数说明
参数
参数 类型 说明
instid 字符串 合约名称
direction 字符串 多仓"long", 空仓“short”
feild str 仅支持“volume”总仓位,“yesvol”昨仓仓位,“postcost”持仓成本三项
返回值
若该账户持仓表中该合约该方向该字段值存在,则返回该值,否则返回0

示例

print(context.getAccountPosition("AU2206.SFE",'long','volume'))

返回值

10

注:若会有多策略并行并有重合合约的情况下,请谨慎使用改接口,很可能把别的策略持仓当做本策略进行处理,引起不必要的问题。对于一般情况更建议使用context.getPosition接口来获取本策略仓位

获取当前策略持仓

context.position

dict类型,以合约名为key的持仓列表。

▼ 持仓字段名
字段名 说明
volume 持仓量
poscost 持仓成本
yesvol 昨仓量

示例

print(context.position)

返回值

{'HC2109.SFE': {'long': {'poscost': 52700.0, 'volume': 1, 'posProf': 0, 'yesvol': 1}, 'short': {'volume': 0, 'poscost': 0, 'yesvol': 0}}}

获取当前策略持仓函数

context.getPosition(instid, direction, field)

本函数用于获取本策略持仓仓位信息。尤其当多策略并行时,可以查当前策略的合约仓位。若当前合约尚且不存在于context.position中,该函数返回0,避免抛出KeyError异常。相对于直接调用context.position,改函数避免了调用前先判断Key是否存在的麻烦。

▼ 函数说明
参数
参数 类型 说明
instid 字符串 合约名称
direction 字符串 多仓"long", 空仓“short”
feild str 仅支持“volume”总仓位,“yesvol”昨仓仓位,“postcost”持仓成本三项
返回值
若该账户持仓表中该合约该方向该字段值存在,则返回该值,否则返回0

示例

print(context.getPosition("AU2206.SFE",'long','volume'))

返回值

5

获取当前日线数据

context.getDailyData(instid)

本函数用于datamode为‘daily’频率的策略在onBar调用时获取当日的日Bar数据。 拿当前日数据可以和get_price获取的历史日线行情无缝连接。(推荐使用pd.concat连接)

▼ 函数说明
参数
参数 类型 说明
instid 字符串 合约名称
返回值
pandas.DataFrame

示例

print(context.getDailyData('AG2212.SFE'))

结果

                       open   close    high     low  volume       money  \
2021-01-08 00:00:00  5827.0  5783.0  5841.0  5767.0     580  50433915.0   
                    position  upperlimit  lowerlimit  presett  preclose  
2021-01-08 00:00:00    1213.0      6399.0      5236.0   5818.0    5818.0

当前结算参数表

context.instsett

dict类型。以合约名为key的合约结算参数表. 比如方位'RB2205.SFE'的做多保证金率为context.instsett['RB2205.SFE'] ['marglong']。

▼ 字段名
字段名 说明
instid 合约名
marglong 做多保证金率
margshort 做空保证金率
openfeerate 开仓手续费率按比例
closefeerate 平仓手续费率按比例
openfee 开仓手续费按绝对值
closefee 平仓手续费按绝对值
closeetodayrate 平今倍数
refprice 参考价格
volmult 每手多少数量(比如吨)
ticksize 最小价格变动值

备注:

  • 商所是平今时候开仓和平仓都有倍数,为了简单方便,都算在平今倍数中了。比如生猪平今开平仓都是2倍,那么不计算开仓,仅计算平今倍数为3
  • 参考价为交易所网站给出参考挂牌价,有些比如中金所产品没有这个价格,设置为0.

示例

print(context.instsett)

返回值

{'cu2109.SFE': {'instid': 'CU2201_SFE', 'marglong': 10.0, 'margshort': 10.0, 'openfeerate': 5e-05, 'closefeerate': 5e-05, 'openfee': 0.0, 'closefee': 0.0, 'closetodayrate': 2.0, 'refprice': 59810.0, 'volmult': 5, 'ticksize': 10}}

当前数据时间

context.curtime

pandas.Timestamp类型, 在回测中,该时间为当前最新一条数据时间,若策略datamode为‘tick’, 该时间为tick时间,若为‘minute’,改时间为最新一条分数数据时间。但在模拟或者实盘中,该时间始终为tick时间。

示例

print(context.curtime)

返回值

'2020-11-19 00:00:00'

当前交易日

context.tradingday

字符串类型, 返回当前交易日,若为晚盘,一般为下一个工作日。

示例

print(context.tradingday)

返回值

'20201125'

bar数据时间

context.bartime

pandas.Timestamp类型, 返回当前最新一个分钟bar的分钟时间。只对分钟bar的策略有效。

示例

print(context.bartime)

返回值

'2020-11-18 00:00:00'

注:

只有在datamode为"minute"的时候context.bartime才有效,请仅当datamode为“minute'的时候,’在onBar函数中使用。

其他系统接口

下单接口

make_order(context, instid, direction, price, volume, ordertype="limit",action="close",closetype='close')
函数说明
参数
参数 类型 说明
instid str 合约代码
direction int 1代表做多, -1代表做空. 若为平仓, 平多仓是-1, 平空仓是1
price float 限价单使用的价格, 若为市价单该价格将不被使用, 仅仅用于记录返回给用户.
volume int 下单量.下多少手
ordertype str 默认为'limit',仅仅支持'limit'限价单和'market'市价单两种.
action str 默认为'close',支持 'open'开仓, 'close'平仓两种.下单先平掉反方向持仓, 多余部分再开仓.
closetype str 默认为‘auto’, 支持‘auto’自动, ‘closetoday’平今,‘closetyesterday’平昨。开仓此项无效,平仓使用 ‘auto‘,会优先平昨仓。
action str 默认为'open'.支持 'open'开仓, 'close'平仓两种.下单先平掉反方向持仓, 多余部分再开仓.
timecond str 默认为'GFD'。支持三种模式: 'GFD'当日有效, 'FAK'即时有效,能成交多少成交多少,未成交部分自动撤单。‘FOK’要么全部成交,要么全部撤单.
返回值
返回值为一个元组(retval, orderlist),比如(0, [31300031])代表下单成功,订单号31300031,(-1,[])代表下单失败
元素 类型 说明
retval int 返回0代表下单成功,负数代表下单失败的原因类型。
orderlist list 下单失败返回空list:[], 若下单成功,返回订单编号列表,比如[32512330001,32512330002],用于撤单时使用.

示例

#以5000的价格对合约RB2205.SFE下平空的限价单,数量为12手,只平今仓。
make_order(context,instid='RB2205.SFE',direction=1,price=5000,volume=12, \
ordertype="limit",action="close",closetype='closetoday')

返回值

(0, [32512330001])

撤单接口

cancel_order(context, orderid)
函数说明
参数
参数 类型 说明
orderid int 订单编号,用于撤单时使用. 若开仓失败(比如资金不够), 返回-1.若为0则撤掉所有未成交的订单
返回值
0代表成功, -1失败代表没有找到订单

示例

#撤掉所有未成交订单
cancel_order(context, 0)

返回值

0

对冲标记函数

该函数用于在对冲策略中记录交易点,方便画回测结果图或者模拟监控图的时候显示对冲点以及根据对冲公式计算所得的数值。

record_hedge_point(context, action, dirstr, volume)
▼ 函数说明
参数
参数 类型 说明
context 系统数据接口 系统数据接口
action str 支持 'open'开仓, 'close'平仓两种
dirstr str 订单方向,必须属于['long', 'short'].由用户自己定义当前条件属于做多还是做空
volume int 下单量,由用户自己定义在当前条件下的下单手数。
返回值

注:若策略没有在构造函数中初始化self.formula ,系统认为该策略是非对冲策略,该函数将不会有任何作用。

示例

record_hedge_point(context, action='open', dirstr='long', volume=1)

bar数据获得函数

该函数用于在获得bar行情数据

get_bar(context,freq, count=None)
▼ 函数说明
参数
参数 类型 说明 默认值
context 系统数据接口 系统数据接口
freq int 分钟级bar数据采样频率,调用时可以用context.freq获得当前采样频率作为输入值
count int 数据数量,获得的数据数量 None,表示当日所有数据
返回值,dict类型,key值为合约名,每个合约的value是一个dataframe。dataframe字段名如下
字段名 类型 描述
time int 时间的数字表达
open float 开盘价
close float 收盘价
high float 最高价
low float 最低价
volume int 成交量
money float 成交额
upperlimit float 涨停价
lowerlimit float 跌停价
position float 持仓量
presett float 昨结算价
preclose float 昨收盘价
tradingday str 交易日

示例

get_bar(context,3, count=5)

返回值

{'RB2206.SFE':                                time    open   close    high     low  volume  \
time1                                                                         
2022-04-12 15:00:00  20220412150000  5019.0  5046.0  5059.0  5019.0   196.0   
2022-04-12 14:57:00  20220412145700  5019.0  5039.0  5059.0  5019.0   189.0   
2022-04-12 14:54:00  20220412145400  5019.0  5039.0  5059.0  5019.0   189.0   
2022-04-12 14:51:00  20220412145100  5019.0  5044.0  5059.0  5019.0   173.0   
2022-04-12 14:48:00  20220412144800  5019.0  5042.0  5059.0  5019.0   170.0   

                         money  position  presett  preclose  lowerlimit  \
time1                                                                     
2022-04-12 15:00:00  9873960.0    5182.0   4993.0    4954.0      4493.0   
2022-04-12 14:57:00  9520740.0    5179.0   4993.0    4954.0      4493.0   
2022-04-12 14:54:00  9520740.0    5179.0   4993.0    4954.0      4493.0   
2022-04-12 14:51:00  8714450.0    5177.0   4993.0    4954.0      4493.0   
2022-04-12 14:48:00  8563150.0    5176.0   4993.0    4954.0      4493.0   

                     upperlimit  tradingday  
time1                                        
2022-04-12 15:00:00      5492.0  20220412.0  
2022-04-12 14:57:00      5492.0  20220412.0  
2022-04-12 14:54:00      5492.0  20220412.0  
2022-04-12 14:51:00      5492.0  20220412.0  
2022-04-12 14:48:00      5492.0  20220412.0  }
Copyright © QUANTEASE Team all right reserved,powered by Gitbook该文件修订时间: 2023-06-29 11:18:32

results matching ""

    No results matching ""