卡尔曼策略新增md文件

This commit is contained in:
2025-11-07 16:37:16 +08:00
parent 2eec6452ee
commit 2ae9f2db9e
89 changed files with 39954 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
import numpy as np
import pandas as pd
from typing import Optional, Dict, Any, List
from collections import deque
# 假设这些是你项目中的模块
from src.core_data import Bar, Order
from src.strategies.base_strategy import Strategy
from src.algo.TrendLine import calculate_latest_trendline_values_v2
class PriceRangeVolumeIntensityStrategy(Strategy):
"""
价格区间成交量强度策略 (V11 - 市场冲击强度版):
- 【核心修改】策略的强度指标从单纯的 `volume` 升级为 `volume * (bar.high - bar.low)`。
- 这个新指标能更准确地衡量市场的“冲击力”或“有效动能”,过滤掉高换手但价格停滞的无效信号。
- 继承了 V10 版本的高效无状态 deque 实现,仅改变了指标的输入源。
"""
def __init__(
self,
context: Any,
main_symbol: str,
strategy_mode: str,
trade_volume: int = 1,
trendline_n: int = 50,
intensity_kappa: float = 0.1,
intensity_lookback: int = 24,
intensity_entry_percent: float = 0.95,
intensity_exit_percent: float = 0.50,
order_direction: Optional[List[str]] = None,
enable_log: bool = True,
):
super().__init__(context, main_symbol, enable_log)
self.main_symbol = main_symbol
self.trade_volume = trade_volume
if strategy_mode not in ['TREND', 'REVERSION']:
raise ValueError(f"strategy_mode 必须是 'TREND''REVERSION', 但收到了 '{strategy_mode}'")
self.strategy_mode = strategy_mode
self.params = {
"order_direction": order_direction if order_direction is not None else ["BUY", "SELL"],
"trendline_n": trendline_n,
"intensity_kappa": intensity_kappa,
"intensity_lookback": intensity_lookback,
"intensity_entry_percent": intensity_entry_percent,
"intensity_exit_percent": intensity_exit_percent,
}
self.weights = np.exp(-self.params['intensity_kappa'] * np.arange(self.params['intensity_lookback'], 0, -1))
self.intensity_window: Optional[deque] = None
self.pos_meta: Dict[str, Dict[str, Any]] = {}
print(f"PriceRangeVolumeIntensityStrategy (V11) initialized.")
print(f"--- Strategy Mode SET TO: {self.strategy_mode} ---")
print(f"Intensity metric: volume * (high - low)")
def _calculate_single_intensity(self, metric_slice: np.ndarray) -> float:
"""根据一段“市场冲击”指标切片,计算最新的一个强度值。"""
intensity_unscaled = np.dot(metric_slice, self.weights)
return intensity_unscaled * self.params['intensity_kappa']
def on_init(self):
super().on_init()
self.pos_meta.clear()
self.intensity_window = None
def on_open_bar(self, open_price: float, symbol: str):
bar_history = self.get_bar_history()
lookback = self.params['intensity_lookback']
min_bars_required = max(self.params['trendline_n'] + 2, 2 * lookback)
if len(bar_history) < min_bars_required:
return
# --- 【核心修改】计算新的“市场冲击”指标序列 ---
# 替代了之前的 all_volumes
market_impact_metric = np.array(
[(b.high - b.low) * 1 for b in bar_history],
dtype=float
)
# 简单的零值处理,防止 (high-low) 为 0 或负数(异常数据)导致的问题
market_impact_metric[market_impact_metric <= 0] = 1e-9
# --- 策略预热 (Warm-up) 与 增量更新 (逻辑不变,数据源已更新) ---
if self.intensity_window is None:
self.intensity_window = deque(maxlen=lookback)
print("Warming up the market impact intensity window...")
for i in range(len(market_impact_metric) - lookback, len(market_impact_metric)):
metric_slice = market_impact_metric[i - lookback : i]
intensity_value = self._calculate_single_intensity(metric_slice)
self.intensity_window.append(intensity_value)
print("Warm-up complete.")
else:
latest_metric_slice = market_impact_metric[-lookback:]
latest_intensity_value = self._calculate_single_intensity(latest_metric_slice)
self.intensity_window.append(latest_intensity_value)
self.cancel_all_pending_orders(symbol)
pos = self.get_current_positions().get(symbol, 0)
# --- 平仓与开仓逻辑 (完全不变,因为它们依赖于 intensity_window 的结果) ---
latest_intensity = self.intensity_window[-1]
# 1. 平仓逻辑
meta = self.pos_meta.get(symbol)
if meta and pos != 0:
exit_threshold = np.quantile(list(self.intensity_window), self.params['intensity_exit_percent'])
if latest_intensity < exit_threshold:
self.log(f"[{self.strategy_mode}模式] 市场冲击强度平仓信号,平仓。")
self.send_market_order("CLOSE_LONG" if meta['direction'] == "BUY" else "CLOSE_SHORT", abs(pos))
del self.pos_meta[symbol]
return
# 2. 开仓逻辑
if pos == 0:
signal = self._calculate_entry_signal(
self.strategy_mode, bar_history, self.params, self.intensity_window
)
if signal and signal in self.params['order_direction']:
self.log(f"[{self.strategy_mode}模式] 市场冲击强度开仓信号: {signal}")
self.send_open_order(signal, open_price, self.trade_volume)
# _calculate_entry_signal 函数完全不变,因为它只消费 intensity_window
def _calculate_entry_signal(self, mode: str, bar_history: List[Bar], params: Dict, intensity_window: deque) -> \
Optional[str]:
latest_intensity_value = intensity_window[-1]
entry_threshold = np.quantile(list(intensity_window), params['intensity_entry_percent'])
if not (latest_intensity_value > entry_threshold):
return None
close_prices = np.array([b.close for b in bar_history])
prices_for_trendline = close_prices[-params['trendline_n'] - 1:-1]
trend_upper, trend_lower = calculate_latest_trendline_values_v2(prices_for_trendline)
if trend_upper is not None and trend_lower is not None:
prev_close = bar_history[-2].close
last_close = bar_history[-1].close
upper_break_event = last_close > trend_upper and prev_close < trend_upper
lower_break_event = last_close < trend_lower and prev_close > trend_lower
if upper_break_event: return "BUY" if mode == 'TREND' else "SELL"
if lower_break_event: return "SELL" if mode == 'TREND' else "BUY"
return None
# 其他辅助函数 (send_order, on_rollover) 保持不变
def send_open_order(self, direction: str, entry_price: float, volume: int):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order_direction = "BUY" if direction == "BUY" else "SELL"
order = Order(id=order_id, symbol=self.symbol, direction=order_direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="OPEN")
self.send_order(order)
self.pos_meta[self.symbol] = {
"direction": direction, "volume": volume, "entry_price": entry_price
}
self.log(
f"发送开仓订单 ({self.strategy_mode}): {direction} {volume}手 @ Market Price (执行价约 {entry_price:.2f})")
def send_market_order(self, direction: str, volume: int):
current_time = self.get_current_time()
order_id = f"{self.symbol}_{direction}_{current_time.strftime('%Y%m%d%H%M%S')}"
order = Order(id=order_id, symbol=self.symbol, direction=direction, volume=volume, price_type="MARKET",
submitted_time=current_time, offset="CLOSE")
self.send_order(order)
self.log(f"发送平仓订单: {direction} {volume}手 @ Market Price")
def on_rollover(self, old_symbol: str, new_symbol: str):
super().on_rollover(old_symbol, new_symbol)
self.cancel_all_pending_orders(new_symbol)
self.pos_meta.clear()
self.intensity_window = None