开发量化策略快速教程
由qxiao创建,最终由qxiao 被浏览 739 用户
BigTrader是宽邦科技推出的致力于为用户提供便捷、功能强大的交易引擎。
在量化研究的过程中,量化研究员(宽客)需要在历史数据里回放模拟,验证策略效果,这就是BigTrader交易引擎的应用场景。
首先,构建简单但能运行的策略
BigQuant平台回测主要使用bigtrader中initialize函数和handle_data函数,initialize为策略初始化函数,只触发一次。可以在该函数中初始化一些变量,如读取配置等;handle_data函数为行情通知函数,频率支持日线和分钟。
# 初始化函数,只执行一次
def initialize(context):
print('初始化函数')
# 数据处理函数,每个周期执行一次
def handle_data(context, data):
pass
# 导入包
from bigmodule import M
# 设置回测起始结束时间、市场、标的,字典格式
backtest_data = {
"start_date":'2024-01-01',
'end_date':'2024-10-08',
'market':'cn_stock',
'instruments':['600519.SH']
}
# 启动回测(传入上述回测字典数据)
m5 = M.bigtrader.v30(
data=backtest_data,
start_date='',
end_date='',
initialize=initialize,
handle_data=handle_data,
capital_base=500000,
frequency="""daily""",
product_type="""股票""",
rebalance_period_type="""交易日""",
rebalance_period_days="""5""",
rebalance_period_roll_forward=True,
backtest_engine_mode="""标准模式""",
before_start_days=0,
volume_limit=1,
order_price_field_buy="""open""",
order_price_field_sell="""open""",
benchmark="""沪深300指数""",
plot_charts=True
)
点击运行,得到以下日志和回测绩效。
可以看到,初始化函数的内容在日志中print出来,因为主函数中啥也没做,所以策略没有交易,资金没有变化,累积收益率曲线走平。
其次,查看回测K线日期和回测标的、持仓
回测函数有两个参数,一个是context,表示策略信息,比如策略的持仓、资金、权益等,是一个全局变量,另一个是data, 表示回测的k线数据。
如果我们丰富数据处理函数的内容,通过context和data接口的方式查看当前回测K线、策略标的、策略持仓。
# 交易引擎:数据处理函数,每个周期执行一次
def handle_data(context, data):
# 输出当前日期和数据
positions = context.get_account_positions()
print(f"当前日期: {data.current_dt.date()}", '股票标的:', context.instruments, '策略持仓:', positions )
运行日志如下:
因为数据处理函数中,只打印了些信息,但没有order操作,所以策略持仓是空的。
最后,构建一个买入并持有策略
买入并持有指第一天买入股票,一直持有,主要介绍下策略如何下单。
# 交易引擎:初始化函数,只执行一次
def initialize(context):
from bigtrader.finance.commission import PerOrder
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
context.ins = context.instruments
# 交易引擎:数据处理函数,每个周期执行一次
def handle_data(context, data):
positions = context.get_account_positions() # 通过context查看持仓
if not positions:
for stock in context.instruments :
context.order(stock, 100) # 买入100股
print('买入全仓股票')
from bigmodule import M
backtest_data = {
"start_date":'2024-01-01',
'end_date':'2024-10-08',
'market':'cn_stock',
'instruments':['600519.SH']
}
m5 = M.bigtrader.v30(
data=backtest_data,
initialize=initialize,
handle_data=handle_data,
capital_base=200000,
frequency="""daily""",
product_type="""股票""",
rebalance_period_type="""交易日""",
rebalance_period_days="""1""",
rebalance_period_roll_forward=True,
backtest_engine_mode="""标准模式""",
before_start_days=0,
volume_limit=1,
order_price_field_buy="""open""",
order_price_field_sell="""open""",
benchmark="""沪深300指数""",
plot_charts=True
)
运行日志如下:
我们看到在20240103日买入100股的贵州茅台。
回测绩效曲线如下:
因为初期买入100股贵州茅台,因此累计收益率会随着每日收盘价的变化而变化。一般关注年化收益、夏普比率、最大回测指标。
回测模块用到的参数:
- data: data,可选,输入数据或初始参数,可以在策略逻辑中通过 context.data 访问
- initialize: 可选,代码,初始化函数,整个回测中只在最开始时调用一次,用于初始化一些账户状态信息和策略基本参数,context也可以理解为一个全局变量,在回测中存放当前账户信息和策略基本参数便于会话。
- handle_data: 可选,代码,K线处理函数,该函数每个单位时间会调用一次, 如果按分钟,则每分钟调用一次。在交易中,可以通过对象data获取单只股票或多只股票的时间窗口价格数据。一般策略的交易逻辑和订单生成体现在该函数中。
- capital_base: 可选,浮点数,默认值1000000,最大值1.7976931348623157e+308,最小值0,初始资金
- frequency:必选,枚举,默认值daily,可选值['daily','minute','tick','tick2'],数据频率:日线 (daily),分钟线 (minute),快照(tick),逐笔(tick2)
- product_type:必选,枚举,默认值股票,可选值['股票','期货','期权','基金','可转债','自动'],产品类型:股票(stock), 期货(future), 期权(option), 基金(fund), 可转债(cbond), 自动(none)
- rebalance_period_type:必选,枚举,默认值交易日,可选值['交易日','周度交易日','月度交易日','季度交易日','年度交易日','自然日','周度自然日','月度自然日','季度自然日','年度自然日','用户自定义','trading_days','weekly_trading_days','monthly_trading_days','quarterly_trading_days','yearly_trading_days','natural_days','weekly_days','monthly_days','quarterly_days','yearly_days'],调仓周期类型
- rebalance_period_days:可选,字符,默认值1,调仓周期日期,多个日期数值用英文逗号分隔,例如 月度交易日 3,-5,表示每月的第三个交易日和导数第五个交日易
- backtest_engine_mode:必选,枚举,默认值标准模式,可选值['自动','极速模式','标准模式'],回测引擎模式, 标准模式: 基于K线事件精确回测; 极速模式: 高性能向量化回测, 目前只支持部分场景; 自动: 如果极速模式可用,优先选择极速模式
- before_start_days:可选,整数,默认值0,最大值2147483647,最小值-2147483648,历史数据向前取的天数
- volume_limit:可选,浮点数,默认值1,最大值1,最小值0,成交率限制:执行下单时控制成交量参数,默认值2.5%,若设置为1时,不进行成交量检查
- order_price_field_buy:必选,枚举,默认值open,可选值 ,买入点:open=开盘买入,close=收盘买入
- order_price_field_sell:必选,枚举,默认值close,可选值 ,卖出点:open=开盘卖出,close=收盘卖出
- benchmark:必选,枚举,默认值沪深300指数,可选值['沪深300指数','中证500指数','中证1000指数','中证100指数','上证指数','上证50指数','科创50指数','深证成指','创业板指','深证100','北证50成份指数'],基准指数, 参考表 cn_stock_index_bar1d
- plot_charts:必选,布尔,默认值True,显示回测结果图表
此外,我们再通过两个简单策略的实现帮助大家理解交易引擎bigtrader。
双均线策略
策略思想
双均线策略是一种常见的技术分析策略,基于两条不同时间周期的移动平均线(MA)来判断市场趋势并进行买卖操作。该策略的核心思想是通过较短周期和较长周期均线的交叉来捕捉价格趋势的变化。当短期均线向上穿越长期均线时,发出买入信号,预示价格可能进入上涨趋势;当短期均线向下穿越长期均线时,则发出卖出信号,提示价格可能开始下跌。双均线策略能够有效过滤掉市场的短期噪声,帮助投资者跟随中长期趋势进行交易。
在本策略中,本文选取了600519.SH(贵州茅台)作为标的股票。贵州茅台是中国白酒行业的领军者,具有极高的品牌影响力和消费者忠诚度,长期来看股价也展现出较强的上升趋势。通过双均线策略,期望捕捉这只股票在价格趋势中的转折点,从而实现较为稳健的交易收益。
初始化设置
导入数据库和回测模块,方便后续策略运行
from bigmodule import M
import dai
设置参数
设置回测起始日期、结束日期、市场信息和交易标的等参数
data = {
"start_date":'2015-01-01',
'end_date':'2024-10-08',
'market':'cn_stock',
'instruments':['600519.SH']
}
进行回测
本文采取bigTrader进行回测,输入前文准备好的标的和仓位数据,进行回测。由于双均线策略为择时策略,本文根据前文计算的exit_condi和entry_condi书写回测逻辑。具体为:根据回测日期提取当日的进场和出场信号,如果产生相应信号,根据现有持仓和目标持仓进行换仓操作,
# 交易引擎:初始化函数,只执行一次
def initialize(context):
from bigtrader.finance.commission import PerOrder
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
context.ins = context.instruments
# 交易引擎:数据处理函数,每个周期执行一次
def handle_data(context, data):
import pandas as pd
from datetime import datetime, timedelta
dt = data.current_dt.strftime('%Y-%m-%d')
ma5 = data.history(context.ins[0], 'close', 5,'1d').mean()
ma80 = data.history(context.ins[0], 'close', 80,'1d').mean()
positions = context.get_account_positions()
# print(dt, context.ins, ma5, ma80, len(positions), '000002.SZ' in positions)
if (ma5 > ma80) and (context.ins[0] not in positions):
stock = context.ins[0]
context.order_target_percent(stock, 0.5)
print(dt, ma5, ma80, positions, '金叉买入 持半仓')
elif (ma5 < ma80) and (context.ins[0] in positions):
if positions[context.ins[0]].avail_qty > 0:
# context.order(context.ins[0], -positions[context.ins[0]].avail_qty)
stock = context.ins[0]
context.order_target_percent(stock, 0)
print(dt, ma5, ma80, positions, '死叉卖出 持空仓')
m3 = M.bigtrader.v30(
data=data,
initialize=initialize,
handle_data=handle_data,
capital_base=500000,
frequency="""daily""",
product_type="""股票""",
rebalance_period_type="""交易日""",
rebalance_period_days="""1""",
rebalance_period_roll_forward=True,
backtest_engine_mode="""标准模式""",
before_start_days=0,
volume_limit=1,
order_price_field_buy="""open""",
order_price_field_sell="""open""",
benchmark="""沪深300指数""",
plot_charts=True
)
策略源码
https://bigquant.com/codesharev3/a2fc177d-6f4a-4ada-8b94-6b431655e679
\
小市值策略
策略思想
小市值策略是一种基于选取市值较小公司的投资策略,旨在捕捉这些公司在未来可能的高速增长潜力。本策略将股票按照流通市值升序排列,选择市值较小的前3只股票进行持仓,持股周期为5天。每只股票的仓位采用等权重分配,以降低个股风险,平衡收益表现。本策略的核心假设是小市值公司具有更大的增长空间,因此能够在市场中获得超额收益。
初始化设置
设置策略时间区间,导入数据库和回测模块,方便后续策略运行
from bigmodule import M
import dai
# 设置起始时间和终止时间
start_date = '2020-01-01'
end_date = '2024-10-08'
读取数据
使用dai进行数据抽取。首先根据需要的指标书写sql语句抽取数据,本策略主要抽取A股标的流通市值数据,并进行数据清洗。
# 提取股票数据
stock_sql = """
SELECT
date,
instrument,
float_market_cap
FROM cn_stock_prefactors
WHERE list_days > 365
AND pe_ttm > 0
-- 非st
AND st_status = 0
-- 主板
AND list_sector = 1
-- 非停牌
AND suspended = 0
-- 非北证50
AND is_bz50 = 0
"""
stock_data = dai.query(stock_sql, filters={"date": [start_date, end_date]}).df()
进行数据预处理,删除空值
stock_data_cleaned = stock_data.dropna()
进行回测
本文采取bigTrader进行回测,输入前文准备好的标的数据,进行回测(可以按照需要定义和修改交易函数,不需要用到的函数设置为pass)。
# 交易引擎:初始化函数,只执行一次
def initialize_run(context):
from bigtrader.finance.commission import PerOrder
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
# 交易引擎:数据处理函数,每个周期执行一次
def handle_data_run(context, data):
import pandas as pd
# 下一个交易日不是调仓日,则不生成信号
if not context.rebalance_period.is_signal_date(data.current_dt.date()):
return
# 从传入的数据 context.data 中读取今天的信号数据
today_df = context.data[context.data["date"] == data.current_dt.strftime("%Y-%m-%d")]
#设定持仓股票数量
count_num = 100
filtered_df = today_df.sort_values(by='float_market_cap', ascending=True).head(count_num)
target_instruments = set(filtered_df["instrument"])
# 获取当前已持有股票
holding_instruments = set(context.get_account_positions().keys())
# 卖出不在目标持有列表中的股票
for instrument in holding_instruments - target_instruments:
context.order_target_percent(instrument, 0)
# 买入目标持有列表中的股票
for i, x in filtered_df.iterrows():
position = 0.01
context.order_target_percent(x.instrument, position)
m5 = M.bigtrader.v30(
data=stock_data_cleaned,
start_date='',
end_date='',
initialize=initialize_run,
handle_data=handle_data_run,
capital_base=500000,
frequency="""daily""",
product_type="""股票""",
rebalance_period_type="""交易日""",
rebalance_period_days="""5""",
rebalance_period_roll_forward=True,
backtest_engine_mode="""标准模式""",
before_start_days=0,
volume_limit=1,
order_price_field_buy="""open""",
order_price_field_sell="""open""",
benchmark="""沪深300指数""",
plot_charts=True
)
策略源码
https://bigquant.com/codesharev3/c58b768b-6963-439c-8737-593389187e38
\