交易引擎介绍
由anthony_wan创建,最终由small_q 被浏览 468 用户
什么是BigTrader
BigTrader是宽邦科技推出的致力于为用户提供便捷、功能强大的量化策略编写、回测分析、仿真模拟和实盘交易的工具。在量化研究的过程中,量化研究员(宽客)需要在历史数据里回放模拟,验证策略效果,这就是BigTrader交易引擎的应用场景。
交易引擎有哪些优势
- 回测研究贴近真实 交易,最大程度保证回测的准确性
- 回测研究、模拟交易、实盘交易为同一套代码,无需做任务修改
- 交易引擎是一个有体系、结构化的工程框架,能大幅提升策略开发的效率
支持的品种
股票、基金、期货、可转债、指数,未来会支持期权、债券、两融
交易频率
日线、分钟、Tick、逐笔
交易引擎介绍
BigQuant回测引擎为时间驱动回测引擎,当设定好每一根K线后,会根据K线频率读取数据。如当在回测引擎中设置为daily时,回测引擎会按照天从传入数据读取。
回测引擎的运行逻辑为每一根K线运行一次,在当前K线进行下单操作时会在下一根K线开始撮合成交。
由于BigQuant模块间传参均使用内置DataSource格式,以下是将**==DataFrame==与DataSource**互转的方式以及读取方式。
\
DataFrame转为DataSource 格式
#创建DataFrame
df = pd.DataFrame([])
#将DataFrame转为DataSource
df = DataSource.write_df(df)
DataSource转为DataFrame 格式
#例如某个模块为m1,将m1的输出转为DataFrame.
#将 m1模块内的data(DataSource)赋值给变量df
df = m1.data
#将DataSource 转为 DataFrame
df = df.read()
\
回测引擎的调取
可视化版本
搜索hftrade, 确认模块版本为 HFTrade.v2, 可直接在该模块内进行代码修改。
代码版本
# 交易引擎:初始化函数,只执行一次
def m1_initialize_bigquant_run(context):
# 加载预测数据
pass
# 交易引擎:每个单位时间开盘前调用一次。
def m1_before_trading_start_bigquant_run(context, data):
# 盘前处理,订阅行情等
pass
# 交易引擎:tick数据处理函数,每个tick执行一次
def m1_handle_tick_bigquant_run(context, tick):
pass
# 交易引擎:bar数据处理函数,每个时间单位执行一次
def m1_handle_data_bigquant_run(context, data):
pass
# 交易引擎:成交回报处理函数,每个成交发生时执行一次
def m1_handle_trade_bigquant_run(context, trade):
pass
# 交易引擎:委托回报处理函数,每个委托变化时执行一次
def m1_handle_order_bigquant_run(context, order):
pass
# 交易引擎:盘后处理函数,每日盘后执行一次
def m1_after_trading_bigquant_run(context, data):
pass
m1 = M.hftrade.v2(
start_date='2023-01-03',
end_date='2023-01-06',
initialize=m1_initialize_bigquant_run,
before_trading_start=m1_before_trading_start_bigquant_run,
handle_tick=m1_handle_tick_bigquant_run,
handle_data=m1_handle_data_bigquant_run,
handle_trade=m1_handle_trade_bigquant_run,
handle_order=m1_handle_order_bigquant_run,
after_trading=m1_after_trading_bigquant_run,
capital_base=1000000,
frequency='minute',
price_type='真实价格',
product_type='股票',
before_start_days='0',
volume_limit=1,
order_price_field_buy='open',
order_price_field_sell='close',
benchmark='000300.HIX',
plot_charts=True,
disable_cache=False,
replay_bdb=False,
show_debug_info=False,
backtest_only=False
)
Hftrade.v2 回测引擎启动参数
参数 | 数据类型 | 参数功能 | 调用方法 |
---|---|---|---|
instruments | DataSource | 回测引擎会自动订阅日期内股票的日线行情,同时会根据日线时间区间运行回测引擎。 | context.instruments |
options_data | DataSource | 回测引擎接入options_data后,可从options_data读取预测数据,并且根据该数据进行下单。 | context.options |
frequency | str | 可填参数**'daily’’minute’’tick’**,会根据填入的参数更新引擎内置运行时间,以此为依据提取数据,达到切换频率的效果。 | data.current_dt |
\
回测引擎主要函数介绍
回测引擎内置了几类主要函数,会按照顺序依次运行。用户可通过可视化或代码方式对函数内容进行更改,最终实现通过回测引擎达到回测的目的。以下是各类函数的运行逻辑。
\
函数名称 | 函数英文名 | 运行逻辑 |
---|---|---|
初始化函数 | initialize_bigquant_run | 启动回测引擎时运行,只运行一次 |
盘前处理函数 | before_trading_start_bigquant_run | 每日开盘前运行一次 |
K线处理函数 | handle_data_bigquant_run | 每根K线运行一次 |
tick处理函数 | handle_tick_bigquant_run | 每个tick运行一次,仅在频率为’tick’时生效,股票一般3s一次,期货一般 500ms 一次 |
盘后处理函数 | after_trading_bigquant_run | 盘后运行 |
\
重要函数用法示例
\
初始化函数
初始化函数主要用于设置回测引擎的实例参数,通过实例参数可以在之后的模块中实现交易中的需求。
以下是一个示例,假如我们传入context.options是一个字典,字典中data对应着DataSource文件,这时我们可通过下列方法将数据存入回测引擎并设置交易周期。
# m7_ 为模块编号前缀
def m7_initialize_bigquant_run(context):
#=========================== 加载预测数据 ===================================
#传入的options是一个字典,字典中'data'对应着DataSource文件,我们可将DataSource文件转为DataFrame中并存入回测引擎
context.ranker_prediction = context.options['data'].read_df()
context.ranker_prediction.set_index('date',inplace=True) #用日期作为索引,可提高之后数据读写速度
#=======================================功能设置
#设置最大买入股票为5只
context.buy_bum = 5
#T+1 交易
context.set_stock_t1(1)
\
盘前处理函数
盘前处理函数通常用于订阅数据,回测引擎内置自动订阅股票日线数据。当我们需要使用股票分钟数据,或期货数据,期货分钟数据等。我们需要提前订阅行情,来实现最终的下单以及收益的计算。
以下是我们订阅股票分钟行情的示例
def m7_before_trading_start_bigquant_run(context, data):
#订阅股票分钟数据
#获取全部需要订阅的股票代码
instrument = context.instrument
#订阅分钟行情
context.subscribe_bar(instrument, '1m')
context.subscribe_bar(instruments: List[str], frequency: str) 实例方法参数
参数 | 是否必选 | 内容 |
---|---|---|
instrument | 必选 | 标的代码的列表 |
frequency | 默认为 ‘1d’ | 可通过更改参数选择不同的行情进行订阅,可选 ‘1d’ , ‘1m’ |
\
K线处理函数
K线处理函数会在每根K线运行一次,通常我们会在该函数内进行K线数据读取,并且下单。
以下是一个我们使用该函数进行数据并下单的示例。
\
def m7_handle_data_bigquant_run(context, data):
"""
context: StrategyContext 是交易引擎策略上下文对象,提供下单、获取资金持仓等对象接口
data: BarDatas 是K线集合对象,提供了访问当前时间,K线价格等接口
"""
#创建买入列表
buy_list = []
#==================== 数据准备
#获取当前时间 pydatetime 类型
time = data.current_dt
#将时间格式转为年月日
date = data.current_dt.date()
#读取预测数据,根据时间进行索引,再将索引重置。
try:
today_data = context.ranker_prediction.loc[date,:]
today_data.reset_index(inplace=True)
except:
return
#假如我们需要选择最小市值的n只股票,n已在初始化模块中设置,以下是实现方法。
#获得当日目标持仓
buy_num = context.buy_num
today_data = today_data.sort_values(by='市值',ascending=True)
buy_list = today_data.instrument.tolist()[:buy_num]
#获取目前持仓列表
holding_list = list(context.get_positions().keys())
#先卖出已持仓股票不在目标持仓中的
for ins in holding_list:
if ins not in buy_list:
context.order_target(ins, 0)
#买入目标持仓中,未持仓的股票
for ins in buy_list:
if ins not in holding_list:
context.order_percent(ins, 0.02)
\
实例方法介绍
\
【查询】实例方法
\
单只标的持仓信息查询 context.get_position(instrument: str, direction = Direction.NONE)
当查询单只标的持仓信息时,可使用 context.get_position() 来获取该标的信息。
实例参数 | 参数类型 | 是否必填 | 参数描述 |
---|---|---|---|
instrument | str | 是 | 查询传入参数标的的持仓信息 |
示例
def m7_handle_data_bigquant_run(context, data):
instrument = '000001.SZA'
#获取股票持仓信息
pos = context.get_position(instrument)
print(pos)
通过以上代码,将返回一个字典,该字典数据格式如下。
StockPosition(bkt000,002875.SZA,LONG,current_qty:2100,avail_qty:0,cost_price:9.44,last_price:9.44,margin:0.0)
返回值 | 返回值含义 | 获取方式 |
---|---|---|
current_qty | 当前持仓 | context.get_position(ins).current_qty |
avail_qty | 可用持仓 | context.get_position(ins).avail_qty |
cost_price | 持仓成本 | context.get_position(ins).cost_price |
last_price | 最新价格 | context.get_position(ins).last_price |
margin | 保证金占用 | context.get_position(ins).margin |
last_sale_date | 最后交易日 | context.get_position(ins).last_sale_date |
\
多只标的持仓信息查询 context.get_positions()
当查询多只标的持仓信息时可以使用 context.get_positions()来获取标的的信息。
实例参数 | 参数类型 | 是否必须 | 参数描述 |
---|---|---|---|
instrument | list | 是 | 标的的列表 |
direction | str | 否 | 可通过 direction=Direction.LONG/SHORT进行持仓方向过滤 |
示例
def m7_handle_data_bigquant_run(context, data):
instruments = ['000001.SZA','000002.SZA']
#获取股票持仓信息
pos = context.get_positions(instruments)
print(pos)
通过以上代码,可以获得一个如下字典:
{'603176.SHA': StockPosition(bkt000,603176.SHA,LONG,current_qty:0,avail_qty:0,cost_price:0.0,last_price:2.97,margin:0.0),
'600768.SHA': StockPosition(bkt000,600768.SHA,LONG,current_qty:2000,avail_qty:0,cost_price:9.72,last_price:9.57,margin:0.0)}
返回值 | 返回值含义 | 获取方式 (注: instrument为股票代码,instrument_list为股票代码列表) |
---|---|---|
keys() | 全部持仓列表 | context.get_positions(instrument_list).keys() |
current_qty | 持仓数量 | context.get_positions(instrument_list).instrument.current_qty |
avail_qty | 可用持仓 | context.get_positions(instrument_list).instrument.avil_qty |
cost_price | 持仓成本 | context.get_positions(instrument_list).instrument.cost_price |
last_price | 最新价格 | context.get_positions(instrument_list).instrument.last_price |
last_sale_date | 最后交易日 | context.get_positions(instrument_list).instrument.last_sale_date |
\
查询当前日期 data.current_dt
可以通过下列方法获取当前日期,主要用于从引擎中提取当日数据使用.
通常我们在初始化时将全部数据读取进入引擎,并将index转为日期形式,在每日k线处理函数运行时,获取当前日期。通过当前日期从全部数据中获取当日数据。
以下是一个示例
#初始化模块中将全部数据
def m7_initialize_bigquant_run(context):
#=========================== 加载预测数据 ===================================
#传入的options是一个字典,字典中'data'对应着DataSource文件,我们可将DataSource文件转为DataFrame中并存入回测引擎
#将全部数据存入 all_data.并重新设定索引
context.all_data = context.options['data'].read_df()
context.all_data.set_index('date',inplace=True) #用日期作为索引,可提高之后数据读写速度
def m7_handle_data_bigquant_run(context, data):
#获取当前时间 pydatetime
time = data.current_dt
#将时间格式转为年月日
date = data.current_dt.date()
#读取数据,根据时间进行索引,再将索引重置。
try:
today_data = context.all_data.loc[date,:]
today_data.reset_index(inplace=True)
except:
return
\
查询当前账户投资组合信息 context.portfolio
可以通过使用 context.portfolio查询当前账户信息
实例方法 | 返回值含义 | 获取方式 |
---|---|---|
positions_value | 持仓市值 | context.portfolio.positions_value |
portfolio_value | 总资产(资金+持仓市值) | context.portfolio.portfolio_value |
cash | 可用资金 | context.portfolio.cash |
actual_cash | 实际资金 | context.portfolio.actual_cash |
\
查询当前标的价格 data.history( )
可通过使用 data.history( ) 获取股票当前价格
实例参数
参数 | 类型 | 是否必须 | 参数含义 |
---|---|---|---|
instrument | str | 是 | 需要获取的代码 |
fields | list[str] | 是 | 需要获取的字段,如 [“close“, “volume“] |
bar_count | int | 是 | 需要的Bar条数 |
frequency | str | 默认 ‘1d’ | 可选 ‘1d’ ‘1m’ ,按照该频率返回数据 |
以下是一个实例,在回测引擎中获取当日股票分钟数据
def m7_handle_data_bigquant_run(context, data):
#获取股票代码
instrument = '000001.SZA'
now_time = context.current_df
#获取该股票截止至当前分钟的全部日内分钟数据
df = data.history(instrument, ["close", "volume"], 30, '1m')
\
【下单】实例方法
按照数量下单 context.order( )
可通过 context.order( ) 方式进行按数量下单
order(instrument, volume, price=0, offset=Offset.NONE, **kwargs)
实例参数 | 参数类型 | 是否必选 | 参数含义 |
---|---|---|---|
instrument | str | 是 | 需要交易的代码 |
volume | int | 是 | 需要交易的数量,>0表示买入,<0表示卖出 |
price | float | 否 | 交易的价格,默认为0表示市价单 |
order_type | OrderType | 默认为MARKET市价单 | 下单类型 LIMIT:限价单 MARKET:市价单 |
offset | Offset | 开平方向,默认为None | OPEN:开仓 CLOSE:平仓 CLOSETODAY平今 |
以下是一个使用context.order( )下单的示例。
def m7_handle_data_bigquant_run(context, data):
#获取股票代码
instrument = '000001.SZA'
#获取当前价格
price = data.current(instrument, "close")
#获取当前账户现金
cash = context.portfolio.cash
#计算买入数量
buy_num = cash//price
#买入
context.order(instrument, buy_num)
\
按照目标持仓金额下单 context.order_value()
可通过 context.order_value( ) 方式进行按目标持仓金额下单。
order_value(instrument, value, price=0, **kwargs)
实例参数
参数类型 | 是否必选 | 参数含义 | |
---|---|---|---|
instrument | str | 是 | 需要买入的代码 |
value | int | 是 | 需要买入的金额 |
price | float | 否 | 交易的价格,默认为0表示市价单 |
order_type | OrderType | 默认为MARKET市价单 | 下单类型 LIMIT:限价单 MARKET:市价单 |
以下是一个使用 context.order_value( ) 下单的示例。
def m7_handle_data_bigquant_run(context, data):
#获取股票代码
instrument = '000001.SZA'
#获取当前价格
price = data.current(instrument, "close")
#获取当前账户现金
cash = context.portfolio.cash
#计算要买入的现金,假如在这里为半仓买入
buy_cash = cash * 0.5
#买入
context.order(instrument, buy_cash)
\
按照目标持仓百分比下单 context.order_percent( )
当买入某只标的是,如希望最终可以按照某百分比持仓。可通过 context.order_percent( ) 方式进行按目标持仓百分比下单,通常用于买单。
order_percent(instrument, percent, price=0, **kwargs)
实例参数
参数类型 | 是否必选 | 参数含义 | |
---|---|---|---|
instrument | str | 是 | 需要买入的标的代码 |
percent | int | 是 | 目标持仓百分比 |
price | float | 否 | 交易的价格,默认为0表示市价单 |
order_type | OrderType | 默认为MARKET市价单 | 下单类型 LIMIT:限价单 MARKET:市价单 |
以下是一个使用 context.order_percent( ) 下单的示例。
def m7_handle_data_bigquant_run(context, data):
#获取股票代码
instrument = '000001.SZA'
#买入50%仓位
context.order_percent(instrument, 0.5)
\
按照目标持仓数量下单 context.order_target( )
如希望将持仓变动到某个固定数量时可通过 context.order_target( )实现,通常用于清空某只标的。
order_target(symbol, target, price=0, order_type=OrderType.LIMIT)
实例参数
参数类型 | 是否必选 | 参数含义 | |
---|---|---|---|
instrument | str | 是 | 需要买入的标的代码 |
target | int | 是 | 目标持仓数量 |
price | float | 否 | 交易的价格,默认为0表示市价单 |
order_type | OrderType | 默认为MARKET市价单 | 下单类型 LIMIT:限价单 MARKET:市价单 |
以下是一个使用 context.order_target( ) 平仓的示例。
def m7_handle_data_bigquant_run(context, data):
#获取全部持仓股票代码
holding_list = list(context.get_positions().keys())
#全部平仓
for ins in holding_list:
context.order_target(ins,0)
\
【其他】实例方法
\
行情订阅 context.subscribe_bar()
订阅K行情后,可在K线处理函数中使用 data.history 的方式获取行情数据
实例参数 | 数据类型 | 是否必须 | 参数含义 |
---|---|---|---|
instrument | list[str] | 是 | 需要订阅的标的代码 |
frequency | str | 否 默认’1m’ | 需要订阅的频率,通常为 ‘1d’ ‘1m’ |
{{heading_numbering_zhCN}}