增加交易策略、交易指标、量化库代码等文件夹

This commit is contained in:
Win_home
2025-04-27 15:54:09 +08:00
parent ca3b209096
commit f57150dae8
589 changed files with 854346 additions and 1757 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,199 @@
from vnpy.trader.constant import Interval
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
from vnpy.trader.object import TickData, BarData
from elite_optionstrategy import (
StrategyTemplate,
Variable,
Parameter,
PortfolioData,
)
class AdvancedSpreadStrategy(StrategyTemplate):
"""基于均线信号做空符合价差的策略"""
author: str = "用Python的交易员"
option_portfolio: str = Parameter("i_o") # 期权产品代码沪深300IO;
underlying_symbol: str = Parameter("iJQ00.DCE") # 标的合约代码,沪深300IFJQ00;
fast_window: int = Parameter(5) # 快速均线周期
slow_window: int = Parameter(60) # 慢速均线周期
risk_level: int = Parameter(40) # 开仓风险度
percent_add: float = Parameter(0.02) # 委托超价比例
otm_level: int = Parameter(0) # 做空期权档位
leg1_ratio: int = Parameter(4) # 顺势腿的比例
leg2_ratio: int = Parameter(1) # 逆势腿的比例
ma_signal: int = Variable(0) # 当前信号多空
trading_size: int = Variable(1) # 当前交易数量
def on_init(self):
"""策略初始化"""
self.write_log("策略初始化")
self.subscribe_options(self.option_portfolio)
self.subscribe_data(self.underlying_symbol)
# 标的信号对象
self.factor = MaFactor(
self.underlying_symbol,
self.fast_window,
self.slow_window
)
# 加载标的历史数据初始化
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
for bar in bars:
self.factor.update_bar(bar)
def on_start(self):
"""策略启动"""
self.write_log("策略启动")
data = load_json("bull_bear_data.json")
self.ma_signal = data.get("ma_signal", 0)
def on_stop(self):
"""策略停止"""
self.write_log("策略停止")
data = {"ma_signal": self.ma_signal}
save_json("bull_bear_data.json", data)
def on_tick(self, tick: TickData):
"""Tick推送"""
pass
def on_bars(self, bars: dict[str, BarData]):
"""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 = 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()
# 做空Put
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
if call and put:
atr_value: float = self.factor.get_atr()
if atr_value:
self.trading_size = int(self.risk_level / atr_value)
self.trading_size = max(self.trading_size, 1)
self.trading_size = 1 # 强制开启最小交易
else:
self.trading_size = 1
self.set_target(put.vt_symbol, -self.trading_size * self.leg1_ratio)
self.set_target(call.vt_symbol, -self.trading_size * self.leg2_ratio)
# 如果均线空头排列,且尚未做空
elif ma_signal < 0 and self.ma_signal >= 0:
# 清空之前的目标
self.clear_targets()
# 做空Call
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
if call and put:
atr_value: float = self.factor.get_atr()
if atr_value:
self.trading_size = int(self.risk_level / atr_value)
self.trading_size = max(self.trading_size, 1)
self.trading_size = 1 # 强制开启最小交易
else:
self.trading_size = 1
self.set_target(call.vt_symbol, -self.trading_size * self.leg1_ratio)
self.set_target(put.vt_symbol, -self.trading_size * self.leg2_ratio)
# 缓存均线多空信号
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, 5, self.update_window_bar)
self.am: ArrayManager = ArrayManager(slow_window + 10)
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.bg.update_bar(bar)
def update_window_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
def get_atr(self) -> float:
"""获取ATR风险度"""
if self.am.inited:
return self.am.atr(self.slow_window)
else:
return 0

View File

@@ -0,0 +1,192 @@
from vnpy.trader.constant import Interval
from vnpy.trader.utility import ArrayManager, BarGenerator, load_json, save_json
from vnpy.trader.object import TickData, BarData
from elite_optionstrategy import (
StrategyTemplate,
Variable,
Parameter,
PortfolioData,
)
class AdvancedSpreadStrategy(StrategyTemplate):
"""基于均线信号做空符合价差的策略"""
author: str = "用Python的交易员"
option_portfolio: str = Parameter("MO") # 期权产品代码
underlying_symbol: str = Parameter("IMJQ00.CFFEX") # 标的合约代码,IMJQ00.CFFEX
aroon_window: int = Parameter(5) # AROON周期
risk_level: int = Parameter(40) # 开仓风险度
percent_add: float = Parameter(0.02) # 委托超价比例
otm_level: int = Parameter(0) # 做空期权档位
leg1_ratio: int = Parameter(2) # 顺势腿的比例
leg2_ratio: int = Parameter(1) # 逆势腿的比例
ma_signal: int = Variable(0) # 当前信号多空
trading_size: int = Variable(1) # 当前交易数量
def on_init(self):
"""策略初始化"""
self.write_log("策略初始化")
self.subscribe_options(self.option_portfolio)
self.subscribe_data(self.underlying_symbol)
# 标的信号对象
self.factor = AroonFactor(
self.underlying_symbol,
self.aroon_window,
)
# 加载标的历史数据初始化
bars = self.load_bars(self.underlying_symbol, 40, Interval.MINUTE)
for bar in bars:
self.factor.update_bar(bar)
def on_start(self):
"""策略启动"""
self.write_log("策略启动")
data = load_json("bull_bear_data.json")
self.ma_signal = data.get("ma_signal", 0)
def on_stop(self):
"""策略停止"""
self.write_log("策略停止")
data = {"ma_signal": self.ma_signal}
save_json("bull_bear_data.json", data)
def on_tick(self, tick: TickData):
"""Tick推送"""
pass
def on_bars(self, bars: dict[str, BarData]):
"""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 = 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()
# 做空Put
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
if call and put:
atr_value: float = self.factor.get_atr()
if atr_value:
self.trading_size = int(self.risk_level / atr_value)
self.trading_size = max(self.trading_size, 1)
else:
self.trading_size = 1
self.set_target(put.vt_symbol, -self.trading_size * self.leg1_ratio)
self.set_target(call.vt_symbol, -self.trading_size * self.leg2_ratio)
# 如果均线空头排列,且尚未做空
elif ma_signal < 0 and self.ma_signal >= 0:
# 清空之前的目标
self.clear_targets()
# 做空Call
call = front_chain.get_option_by_level(cp=1, level=self.otm_level)
put = front_chain.get_option_by_level(cp=-1, level=self.otm_level)
if call and put:
atr_value: float = self.factor.get_atr()
if atr_value:
self.trading_size = int(self.risk_level / atr_value)
self.trading_size = max(self.trading_size, 1)
else:
self.trading_size = 1
self.set_target(call.vt_symbol, -self.trading_size * self.leg1_ratio)
self.set_target(put.vt_symbol, -self.trading_size * self.leg2_ratio)
# 缓存均线多空信号
self.ma_signal = ma_signal
# 执行具体的委托交易
self.execute_trading(price_data, self.percent_add)
class AroonFactor:
"""标的物均线因子(基于均线输出多空信号)"""
def __init__(
self,
vt_symbol: str,
aroon_window: int,
) -> None:
"""构造函数"""
self.vt_symbol: str = vt_symbol
self.aroon_window: int = aroon_window
self.bg: BarGenerator = BarGenerator(self.update_bar, 30, self.update_window_bar)
self.am: ArrayManager = ArrayManager(aroon_window + 10)
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.bg.update_bar(bar)
def update_window_bar(self, bar: BarData) -> None:
"""K线更新"""
self.am.update_bar(bar)
if not self.am.inited:
return
# 计算均线
self.aroon_up, self.aroon_down = self.am.aroon(self.aroon_window)
# 判断信号
if self.aroon_up > self.aroon_down: # and (self.aroon_up > 50)
self.signal = 1
elif self.aroon_up < self.aroon_down: # and (self.aroon_down < 50)
self.signal = -1
else:
self.signal = 0
def get_signal(self) -> int:
"""获取当前多空信号"""
return self.signal
def get_atr(self) -> float:
"""获取ATR风险度"""
if self.am.inited:
return self.am.atr(self.aroon_window)
else:
return 0