增加交易策略、交易指标、量化库代码等文件夹
This commit is contained in:
136
5.课程代码/2.Option_spread_strategy/使用文档/23/23_demo.ipynb
Normal file
136
5.课程代码/2.Option_spread_strategy/使用文档/23/23_demo.ipynb
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载功能模块\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"from vnpy.trader.constant import Interval\n",
|
||||
"\n",
|
||||
"from elite_optionstrategy import BacktestingEngine\n",
|
||||
"\n",
|
||||
"from buy_option_strategy import BuyOptionStrategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 创建回测引擎\n",
|
||||
"engine = BacktestingEngine()\n",
|
||||
"\n",
|
||||
"engine.set_parameters(\n",
|
||||
" interval=Interval.MINUTE,\n",
|
||||
" start=datetime(2022, 1, 1),\n",
|
||||
" end=datetime(2022, 1, 28),\n",
|
||||
" rate=0,\n",
|
||||
" slippage=0.6 + (16 / 100),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"engine.add_strategy(BuyOptionStrategy, {})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 历史数据回放\n",
|
||||
"engine.run_backtesting()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 获取引擎内最新交易日的策略对象\n",
|
||||
"strategy = engine.strategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 获取策略内部对象\n",
|
||||
"portfolio = strategy.get_portfolio(\"IO\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看ChainData\n",
|
||||
"chain = portfolio.get_chain_by_level(0)\n",
|
||||
"chain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain.calculate_synthetic()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看OptionData\n",
|
||||
"option = chain.get_option_by_level(cp=1, level=0)\n",
|
||||
"option"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.9"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "1b43cb0bd93d5abbadd54afed8252f711d4681fe6223ad6b67ffaee289648f85"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
159
5.课程代码/2.Option_spread_strategy/使用文档/23/buy_option_strategy.py
Normal file
159
5.课程代码/2.Option_spread_strategy/使用文档/23/buy_option_strategy.py
Normal file
@@ -0,0 +1,159 @@
|
||||
from vnpy.trader.constant import Interval
|
||||
from vnpy.trader.utility import ArrayManager, BarGenerator
|
||||
from vnpy.trader.object import TickData, BarData
|
||||
|
||||
from elite_optionstrategy import (
|
||||
StrategyTemplate,
|
||||
Variable,
|
||||
Parameter,
|
||||
PortfolioData,
|
||||
ChainData,
|
||||
OptionData,
|
||||
)
|
||||
|
||||
|
||||
class BuyOptionStrategy(StrategyTemplate):
|
||||
"""基于均线信号买入期权的策略"""
|
||||
|
||||
author: str = "用Python的交易员"
|
||||
|
||||
option_portfolio: str = Parameter("IO") # 期权产品代码
|
||||
underlying_symbol: str = Parameter("IFJQ00.CFFEX") # 标的合约代码
|
||||
fast_window: int = Parameter(20) # 快速均线周期
|
||||
slow_window: int = Parameter(120) # 慢速均线周期
|
||||
fixed_size: int = Parameter(1) # 交易的手数
|
||||
percent_add: float = Parameter(0.02) # 委托超价比例
|
||||
|
||||
ma_signal: int = Variable(0) # 当前信号多空
|
||||
|
||||
def on_init(self) -> None:
|
||||
"""策略初始化"""
|
||||
self.write_log("策略初始化")
|
||||
|
||||
self.subscribe_options(self.option_portfolio)
|
||||
self.subscribe_data(self.underlying_symbol)
|
||||
|
||||
# 标的信号对象
|
||||
self.factor: MaFactor = MaFactor(
|
||||
self.underlying_symbol,
|
||||
self.fast_window,
|
||||
self.slow_window
|
||||
)
|
||||
|
||||
# 加载标的历史数据初始化
|
||||
bars: list[BarData] = self.load_bars(self.underlying_symbol, 10, Interval.MINUTE)
|
||||
for bar in bars:
|
||||
self.factor.update_bar(bar)
|
||||
|
||||
def on_start(self) -> None:
|
||||
"""策略启动"""
|
||||
self.write_log("策略启动")
|
||||
|
||||
def on_stop(self) -> None:
|
||||
"""策略停止"""
|
||||
self.write_log("策略停止")
|
||||
|
||||
def on_tick(self, tick: TickData) -> None:
|
||||
"""Tick推送"""
|
||||
pass
|
||||
|
||||
def on_bars(self, bars: dict[str, BarData]) -> None:
|
||||
"""K线推送"""
|
||||
# 回测首先计算标的信号
|
||||
underlying_bar: BarData = bars.pop(self.underlying_symbol, None)
|
||||
if underlying_bar:
|
||||
self.factor.update_bar(underlying_bar)
|
||||
|
||||
# 获取期权组合对象
|
||||
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
|
||||
|
||||
# 更新最新期权价格到组合
|
||||
price_data: dict[str, float] = {}
|
||||
for bar in bars.values():
|
||||
price_data[bar.vt_symbol] = bar.close_price
|
||||
|
||||
portfolio.update_price(price_data)
|
||||
|
||||
# 获取当月期权链
|
||||
front_chain: ChainData = portfolio.get_chain_by_level(0)
|
||||
if not front_chain:
|
||||
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
|
||||
return
|
||||
|
||||
# 计算平值期权
|
||||
front_chain.calculate_atm()
|
||||
|
||||
# 获取当前均线多空信号
|
||||
ma_signal: int = self.factor.get_signal()
|
||||
|
||||
# 如果均线多头排列,且尚未做多
|
||||
if ma_signal > 0 and self.ma_signal <= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值call
|
||||
atm_call: OptionData = front_chain.get_option_by_level(cp=1, level=0)
|
||||
self.set_target(atm_call.vt_symbol, self.fixed_size)
|
||||
# 如果均线空头排列,且尚未做空
|
||||
elif ma_signal < 0 and self.ma_signal >= 0:
|
||||
# 清空之前的目标
|
||||
self.clear_targets()
|
||||
|
||||
# 做多平值put
|
||||
atm_put: OptionData = front_chain.get_option_by_level(cp=-1, level=0)
|
||||
self.set_target(atm_put.vt_symbol, self.fixed_size)
|
||||
|
||||
# 缓存均线多空信号
|
||||
self.ma_signal = ma_signal
|
||||
|
||||
# 执行具体的委托交易
|
||||
self.execute_trading(price_data, self.percent_add)
|
||||
|
||||
|
||||
class MaFactor:
|
||||
"""标的物均线因子(基于均线输出多空信号)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vt_symbol: str,
|
||||
fast_window: int,
|
||||
slow_window: int
|
||||
) -> None:
|
||||
"""构造函数"""
|
||||
self.vt_symbol: str = vt_symbol
|
||||
self.fast_window: int = fast_window
|
||||
self.slow_window: int = slow_window
|
||||
|
||||
self.bg: BarGenerator = BarGenerator(self.update_bar)
|
||||
self.am: ArrayManager = ArrayManager(slow_window + 10)
|
||||
|
||||
self.fast_ma: float = 0
|
||||
self.slow_ma: float = 0
|
||||
|
||||
self.signal: int = 0
|
||||
|
||||
def update_tick(self, tick: TickData) -> None:
|
||||
"""Tick更新"""
|
||||
self.bg.update_tick(tick)
|
||||
|
||||
def update_bar(self, bar: BarData) -> None:
|
||||
"""K线更新"""
|
||||
self.am.update_bar(bar)
|
||||
if not self.am.inited:
|
||||
return
|
||||
|
||||
# 计算均线
|
||||
self.fast_ma = self.am.sma(self.fast_window)
|
||||
self.slow_ma = self.am.sma(self.slow_window)
|
||||
|
||||
# 判断信号
|
||||
if self.fast_ma > self.slow_ma:
|
||||
self.signal = 1
|
||||
elif self.fast_ma < self.slow_ma:
|
||||
self.signal = -1
|
||||
else:
|
||||
self.signal = 0
|
||||
|
||||
def get_signal(self) -> int:
|
||||
"""获取当前多空信号"""
|
||||
return self.signal
|
||||
Reference in New Issue
Block a user