From 21f2adc4a4b631adbbb79a8f9a2628e63b761a03 Mon Sep 17 00:00:00 2001 From: ddrwode <34234@3来 34> Date: Fri, 20 Feb 2026 20:57:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=93=88=E5=93=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reports/strategy_comparison.png | Bin 0 -> 190126 bytes requirements.txt | 9 + strategy/__init__.py | 1 + strategy/ai_strategy.py | 214 +++++++++ strategy/backtest.py | 298 +++++++++++++ strategy/compare.py | 222 ++++++++++ strategy/config.py | 151 +++++++ strategy/data_loader.py | 119 +++++ strategy/feature_engine.py | 204 +++++++++ strategy/indicators.py | 278 ++++++++++++ strategy/stat_strategy.py | 256 +++++++++++ test.py | 2 + 四分之一,五分钟,反手条件充足.py | 694 ++++++++++++++++++++++++++++++ 13 files changed, 2448 insertions(+) create mode 100644 reports/strategy_comparison.png create mode 100644 requirements.txt create mode 100644 strategy/__init__.py create mode 100644 strategy/ai_strategy.py create mode 100644 strategy/backtest.py create mode 100644 strategy/compare.py create mode 100644 strategy/config.py create mode 100644 strategy/data_loader.py create mode 100644 strategy/feature_engine.py create mode 100644 strategy/indicators.py create mode 100644 strategy/stat_strategy.py create mode 100644 test.py create mode 100644 四分之一,五分钟,反手条件充足.py diff --git a/reports/strategy_comparison.png b/reports/strategy_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..27a03770ef3a1f2de16aa0276b01a8120f560653 GIT binary patch literal 190126 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.0 +numpy>=1.24 +ta>=0.11.0 +scikit-learn>=1.3 +lightgbm>=4.0 +xgboost>=2.0 +matplotlib>=3.7 +peewee>=3.16 +loguru>=0.7 diff --git a/strategy/__init__.py b/strategy/__init__.py new file mode 100644 index 0000000..6771cf2 --- /dev/null +++ b/strategy/__init__.py @@ -0,0 +1 @@ +"""52指标AI交易策略系统""" diff --git a/strategy/ai_strategy.py b/strategy/ai_strategy.py new file mode 100644 index 0000000..20f7a0d --- /dev/null +++ b/strategy/ai_strategy.py @@ -0,0 +1,214 @@ +""" +方案B:AI模型训练 + 信号生成 +使用 LightGBM / XGBoost,Walk-Forward 滚动训练 +""" +import json +import joblib +import pandas as pd +import numpy as np +from pathlib import Path +from loguru import logger + +from .config import MODEL_CONFIG as MC, PRIMARY_PERIOD, PROJECT_ROOT +from .feature_engine import prepare_dataset, get_latest_feature_row +from .backtest import BacktestEngine, print_metrics + +SCHEME_B_MODEL_DIR = PROJECT_ROOT / 'models' +SCHEME_B_MODEL_FILE = SCHEME_B_MODEL_DIR / 'scheme_b_last_model.joblib' +SCHEME_B_SCALER_FILE = SCHEME_B_MODEL_DIR / 'scheme_b_scaler.joblib' +SCHEME_B_FEATURES_FILE = SCHEME_B_MODEL_DIR / 'scheme_b_features.json' + + +class AIStrategy: + """AI模型策略 — LightGBM / XGBoost Walk-Forward""" + + def __init__(self, model_type: str = 'lightgbm'): + """ + :param model_type: 'lightgbm' 或 'xgboost' + """ + self.model_type = model_type + self.models = [] # 存储每个窗口训练的模型 + self.feature_importance = None + + def _create_model(self): + """创建模型实例""" + if self.model_type == 'lightgbm': + import lightgbm as lgb + params = MC['lightgbm'].copy() + return lgb.LGBMClassifier(**params) + elif self.model_type == 'xgboost': + import xgboost as xgb + params = MC['xgboost'].copy() + return xgb.XGBClassifier(**params) + else: + raise ValueError(f"不支持的模型类型: {self.model_type}") + + def walk_forward_train(self, X: pd.DataFrame, y: pd.Series, + confidence_threshold: float = 0.45) -> pd.Series: + """ + Walk-Forward 滚动训练与预测 + :param confidence_threshold: 概率阈值,低于此值的预测设为0(观望) + :return: 全部测试窗口拼接的预测信号 + """ + train_size = MC['walk_forward_train_size'] + test_size = MC['walk_forward_test_size'] + step = MC['walk_forward_step'] + + n = len(X) + all_preds = pd.Series(dtype=float) + window_count = 0 + + logger.info(f"Walk-Forward: 数据量={n}, 训练窗口={train_size}, " + f"测试窗口={test_size}, 步长={step}, 置信阈值={confidence_threshold}") + + start = 0 + while start + train_size + test_size <= n: + train_end = start + train_size + test_end = min(train_end + test_size, n) + + X_train = X.iloc[start:train_end] + y_train = y.iloc[start:train_end] + X_test = X.iloc[train_end:test_end] + y_test = y.iloc[train_end:test_end] + + # 训练 + model = self._create_model() + model.fit(X_train, y_train) + self.models.append(model) + + # 预测概率 + 置信度过滤 + proba = model.predict_proba(X_test) + max_proba = proba.max(axis=1) + raw_preds = model.predict(X_test) + + # 置信度不够的设为观望 + filtered_preds = raw_preds.copy() + filtered_preds[max_proba < confidence_threshold] = 0 + + preds = pd.Series(filtered_preds, index=X_test.index) + all_preds = pd.concat([all_preds, preds]) + + # 准确率(用原始预测算) + acc = (raw_preds == y_test).mean() + n_filtered = (max_proba < confidence_threshold).sum() + window_count += 1 + logger.info(f" 窗口 {window_count}: 训练[{start}:{train_end}] " + f"测试[{train_end}:{test_end}] 准确率={acc:.2%} " + f"过滤={n_filtered}/{len(X_test)}") + + start += step + + # 特征重要性(取最后一个模型) + if self.models: + last_model = self.models[-1] + if hasattr(last_model, 'feature_importances_'): + self.feature_importance = pd.Series( + last_model.feature_importances_, index=X.columns + ).sort_values(ascending=False) + + logger.info(f"Walk-Forward 完成: {window_count} 个窗口, " + f"共 {len(all_preds)} 条预测") + return all_preds + + def get_top_features(self, n: int = 20) -> pd.Series: + """获取Top N重要特征""" + if self.feature_importance is not None: + return self.feature_importance.head(n) + return pd.Series(dtype=float) + + def run(self, period: int = None, start_date: str = None, end_date: str = None) -> dict: + """ + 完整运行方案B + 若指定了 start_date/end_date,会向前加载 warm_up_months 月数据用于训练,使回测区间首月即有预测。 + :return: 回测结果 + """ + if period is None: + period = PRIMARY_PERIOD + + logger.info("=" * 60) + logger.info(f"方案B:AI模型策略 ({self.model_type})") + logger.info("=" * 60) + + from .data_loader import load_kline + + # 1. 准备数据:若指定了回测区间,则向前加载预热数据,使区间内从首月就有预测 + load_start, load_end = start_date, end_date + if start_date and end_date: + warm_months = MC.get('warm_up_months', 12) + load_start_ts = pd.Timestamp(start_date) - pd.DateOffset(months=warm_months) + load_start = load_start_ts.strftime('%Y-%m-%d') + logger.info(f"回测区间 [{start_date} ~ {end_date}],向前加载 {warm_months} 月至 {load_start} 用于训练") + + X, y, feature_names, scaler = prepare_dataset(period, load_start, load_end) + + # 2. Walk-Forward 训练 + predictions = self.walk_forward_train(X, y) + + # 3. 回测仅用用户指定区间;将预测对齐到该区间的每根K线 + df = load_kline(period, start_date, end_date) + if df.empty: + logger.warning("回测区间内无K线数据") + return BacktestEngine()._empty_result() + + # 对齐信号:回测区间内有的时间戳用预测,缺失的填 0(观望) + signals = predictions.reindex(df.index, fill_value=0).astype(int) + prices = df['close'] + + # 4. 回测 + engine = BacktestEngine() + result = engine.run(prices, signals) + + print_metrics(result['metrics'], f"方案B: {self.model_type} AI策略") + + # 5. 保存最后一窗模型、scaler、特征列(供实盘 get_live_signal 使用) + if self.models and scaler is not None: + SCHEME_B_MODEL_DIR.mkdir(parents=True, exist_ok=True) + joblib.dump(self.models[-1], SCHEME_B_MODEL_FILE) + joblib.dump(scaler, SCHEME_B_SCALER_FILE) + with open(SCHEME_B_FEATURES_FILE, 'w', encoding='utf-8') as f: + json.dump(feature_names, f, ensure_ascii=False) + logger.info(f"已保存方案B模型: {SCHEME_B_MODEL_FILE}, scaler, {len(feature_names)} 个特征") + + # 6. 输出特征重要性 + top_feat = self.get_top_features(15) + if not top_feat.empty: + logger.info("\nTop 15 重要特征:") + for i, (feat, imp) in enumerate(top_feat.items()): + logger.info(f" {i+1}. {feat}: {imp:.4f}") + + result['feature_importance'] = self.feature_importance + return result + + +def run_ai_strategy(model_type: str = 'lightgbm', period: int = None, + start_date: str = None, end_date: str = None) -> dict: + """方案B快捷入口""" + strategy = AIStrategy(model_type=model_type) + return strategy.run(period, start_date, end_date) + + +def get_live_signal(period: int = None, model_type: str = 'lightgbm', + start_date: str = None, end_date: str = None) -> int: + """ + 使用已保存的方案B模型对当前最新K线生成信号(供实盘/模拟盘调用)。 + 需先运行过 run_ai_strategy 或 AIStrategy().run() 以生成 models/scheme_b_*.joblib 与 features.json。 + :param period: K线主周期,默认 15 + :param model_type: 未使用(模型已固定为磁盘上的 scheme_b_last_model.joblib) + :param start_date, end_date: 可选,限制 load_kline 范围 + :return: 0=观望, 1=做多, 2=做空 + """ + if period is None: + period = PRIMARY_PERIOD + if not SCHEME_B_MODEL_FILE.exists() or not SCHEME_B_SCALER_FILE.exists() or not SCHEME_B_FEATURES_FILE.exists(): + logger.warning("方案B模型未找到,请先运行 AI 策略训练保存模型") + return 0 + model = joblib.load(SCHEME_B_MODEL_FILE) + scaler = joblib.load(SCHEME_B_SCALER_FILE) + with open(SCHEME_B_FEATURES_FILE, 'r', encoding='utf-8') as f: + feature_cols = json.load(f) + X_last = get_latest_feature_row(period, feature_cols, start_date, end_date) + if X_last.empty: + return 0 + X_scaled = scaler.transform(X_last) + pred = model.predict(X_scaled) + return int(pred[0]) diff --git a/strategy/backtest.py b/strategy/backtest.py new file mode 100644 index 0000000..64f82c7 --- /dev/null +++ b/strategy/backtest.py @@ -0,0 +1,298 @@ +""" +回测引擎 — 多空双向、手续费、滑点、绩效统计 +每笔固定名义 100U、100 倍杠杆;同一时间仅一个仓位;最大回撤 300U 硬约束;手续费 90% 返佣 +""" +import pandas as pd +import numpy as np +from loguru import logger +from .config import TRADE_CONFIG as TC, SIGNAL_MAP + + +class BacktestEngine: + """回测引擎:固定每笔 100U 名义、100x,单仓位,最大回撤 300U 内,实付手续费(90% 返佣)""" + + def __init__(self, commission: float = None, slippage: float = None, + initial_capital: float = None, position_size: float = None, + position_notional_usd: float = None, max_drawdown_limit: float = None, + commission_rebate: float = None): + raw_commission = commission if commission is not None else TC['commission'] + rebate = commission_rebate if commission_rebate is not None else TC.get('commission_rebate', 0) + self.commission = raw_commission * (1 - rebate) # 实付手续费(90% 返佣) + self.slippage = slippage or TC['slippage'] + self.initial_capital = initial_capital or TC['initial_capital'] + self.position_size = position_size or TC['position_size'] + self.position_notional_usd = position_notional_usd if position_notional_usd is not None else TC.get('position_notional_usd', self.initial_capital * self.position_size) + self.max_drawdown_limit = max_drawdown_limit if max_drawdown_limit is not None else TC.get('max_drawdown_limit', float('inf')) + + def run(self, prices: pd.Series, signals: pd.Series) -> dict: + """ + 执行回测 + :param prices: 收盘价 Series + :param signals: 信号 Series,值: 0=观望, 1=做多, 2=做空 + :return: 回测结果字典 + """ + df = pd.DataFrame({'price': prices, 'signal': signals}).dropna() + if df.empty: + logger.warning("回测数据为空") + return self._empty_result() + + n = len(df) + capital = self.initial_capital + position = 0 # 持仓数量(正=多头,负=空头) + entry_price = 0.0 + direction = 0 # 当前方向: 0=空仓, 1=多, 2=空 + trades = [] + equity_curve = np.zeros(n) + peak_equity = self.initial_capital # 用于 300U 最大回撤约束 + + for i in range(n): + price = df.iloc[i]['price'] + signal = int(df.iloc[i]['signal']) + + # 计算当前权益 + if position > 0: + equity_curve[i] = capital + position * (price - entry_price) + elif position < 0: + equity_curve[i] = capital + position * (price - entry_price) + else: + equity_curve[i] = capital + current_equity = equity_curve[i] + peak_equity = max(peak_equity, current_equity) + + # 最大回撤硬约束:从峰值回落超过 300U 则不再开新仓(只允许平仓) + drawdown_usd = peak_equity - current_equity + can_open = drawdown_usd < self.max_drawdown_limit + + # 强制止损:持仓浮亏超过初始资金的20%时强制平仓 + if position != 0: + unrealized = position * (price - entry_price) + if unrealized < -self.initial_capital * 0.20: + capital, trade = self._close_position( + capital, position, entry_price, price, df.index[i]) + trades.append(trade) + position = 0 + direction = 0 + continue + + # 资金不足时不开新仓;同一时间仅一个仓位(已有持仓则只能先平再开) + min_capital = self.initial_capital * 0.05 + can_trade = capital > min_capital and can_open + + # 跳过:信号与当前持仓方向相同 + if signal == direction: + continue + + # 每笔固定名义 100U:qty = position_notional_usd / price + notional = self.position_notional_usd + qty = notional / price if price > 0 else 0 + + # 需要换方向或平仓 + if signal == 1 and direction != 1: + # 先平仓 + if position != 0: + capital, trade = self._close_position( + capital, position, entry_price, price, df.index[i]) + trades.append(trade) + position = 0 + + if not can_trade or qty <= 0: + direction = 0 + continue + + # 开多:固定 100U 名义,实付手续费 + cost = notional * (self.commission + self.slippage) + capital -= cost + position = qty + entry_price = price + direction = 1 + + elif signal == 2 and direction != 2: + # 先平仓 + if position != 0: + capital, trade = self._close_position( + capital, position, entry_price, price, df.index[i]) + trades.append(trade) + position = 0 + + if not can_trade or qty <= 0: + direction = 0 + continue + + # 开空:固定 100U 名义 + cost = notional * (self.commission + self.slippage) + capital -= cost + position = -qty + entry_price = price + direction = 2 + + elif signal == 0 and position != 0: + # 平仓 + capital, trade = self._close_position( + capital, position, entry_price, price, df.index[i]) + trades.append(trade) + position = 0 + direction = 0 + + # 最终平仓 + if position != 0: + price = df.iloc[-1]['price'] + capital, trade = self._close_position( + capital, position, entry_price, price, df.index[-1]) + trades.append(trade) + + equity = pd.Series(equity_curve, index=df.index) + trades_df = pd.DataFrame(trades) if trades else pd.DataFrame() + metrics = self._calc_metrics(equity, trades_df) + monthly_pnl = self._monthly_pnl(equity) + + return { + 'equity_curve': equity, + 'trades': trades_df, + 'metrics': metrics, + 'final_capital': capital, + 'monthly_pnl': monthly_pnl, + } + + def _close_position(self, capital, position, entry_price, exit_price, time): + """平仓并返回更新后的capital和交易记录""" + if position > 0: + pnl = position * (exit_price - entry_price) + cost = position * exit_price * (self.commission + self.slippage) + trade_type = '平多' + else: + pnl = -position * (entry_price - exit_price) + cost = abs(position) * exit_price * (self.commission + self.slippage) + trade_type = '平空' + + capital += pnl - cost + trade = { + 'type': trade_type, + 'entry': entry_price, + 'exit': exit_price, + 'pnl': pnl - cost, + 'return_pct': (exit_price / entry_price - 1) * (1 if position > 0 else -1), + 'time': time, + } + return capital, trade + + def _calc_metrics(self, equity: pd.Series, trades: pd.DataFrame) -> dict: + """计算绩效指标""" + if equity.empty: + return self._empty_metrics() + + total_return = (equity.iloc[-1] / self.initial_capital) - 1 + + n_bars = len(equity) + if n_bars > 1: + # 按日聚合收益率计算夏普 + daily_equity = equity.resample('D').last().dropna() + if len(daily_equity) > 1: + daily_returns = daily_equity.pct_change().dropna() + n_days = len(daily_returns) + annualized_return = (1 + total_return) ** (365 / max(n_days, 1)) - 1 if total_return > -1 else -1.0 + sharpe = (daily_returns.mean() / daily_returns.std() * np.sqrt(365) + if daily_returns.std() > 0 else 0) + else: + annualized_return = 0 + sharpe = 0 + else: + annualized_return = 0 + sharpe = 0 + + # 最大回撤(比例与绝对 USDT) + cummax = equity.cummax() + drawdown = (equity - cummax) / cummax.replace(0, np.nan) + max_drawdown = drawdown.min() if not drawdown.empty else 0 + max_drawdown_usd = (cummax - equity).max() if not equity.empty else 0 + + # 按月收益(自然月):用于目标「每月盈利 ≥ 1000U」 + monthly_pnl_usd = None + months_above_1000 = 0 + if not equity.empty and hasattr(equity.index, 'to_period'): + try: + monthly = equity.resample('ME').last().dropna() + if len(monthly) > 0: + monthly_pnl = monthly.diff() + monthly_pnl.iloc[0] = monthly.iloc[0] - self.initial_capital + monthly_pnl_usd = monthly_pnl + months_above_1000 = (monthly_pnl >= 1000).sum() + except Exception: + pass + + # 交易统计 + n_trades = len(trades) + if n_trades > 0: + wins = trades[trades['pnl'] > 0] + losses = trades[trades['pnl'] <= 0] + win_rate = len(wins) / n_trades + avg_win = wins['pnl'].mean() if len(wins) > 0 else 0 + avg_loss = abs(losses['pnl'].mean()) if len(losses) > 0 else 0 + profit_factor = (wins['pnl'].sum() / abs(losses['pnl'].sum()) + if len(losses) > 0 and losses['pnl'].sum() != 0 else float('inf')) + else: + win_rate = 0 + avg_win = 0 + avg_loss = 0 + profit_factor = 0 + + out = { + '总收益率': f'{total_return:.2%}', + '年化收益率': f'{annualized_return:.2%}', + '最大回撤': f'{max_drawdown:.2%}', + '最大回撤(U)': f'{max_drawdown_usd:.2f}', + '夏普比率': f'{sharpe:.2f}', + '总交易次数': n_trades, + '胜率': f'{win_rate:.2%}', + '平均盈利': f'{avg_win:.2f}', + '平均亏损': f'{avg_loss:.2f}', + '盈亏比': f'{profit_factor:.2f}', + '最终资金': f'{equity.iloc[-1]:.2f}', + } + out['月盈利≥1000U的月数'] = months_above_1000 if monthly_pnl_usd is not None else 0 + if monthly_pnl_usd is not None and len(monthly_pnl_usd) > 0: + out['月均盈利(U)'] = f'{monthly_pnl_usd.mean():.2f}' + else: + out['月均盈利(U)'] = '0.00' + return out + + def _monthly_pnl(self, equity: pd.Series): + """按自然月汇总收益(USDT),首月为当月权益 - 初始资金""" + if equity.empty or not hasattr(equity.index, 'to_period'): + return None + try: + monthly = equity.resample('ME').last().dropna() + if len(monthly) == 0: + return None + pnl = monthly.diff() + pnl.iloc[0] = monthly.iloc[0] - self.initial_capital + return pnl + except Exception: + return None + + def _empty_result(self): + return { + 'equity_curve': pd.Series(dtype=float), + 'trades': pd.DataFrame(), + 'metrics': self._empty_metrics(), + 'final_capital': self.initial_capital, + 'monthly_pnl': None, + } + + def _empty_metrics(self): + return { + '总收益率': '0.00%', '年化收益率': '0.00%', '最大回撤': '0.00%', + '最大回撤(U)': '0.00', '夏普比率': '0.00', '总交易次数': 0, '胜率': '0.00%', + '平均盈利': '0.00', '平均亏损': '0.00', '盈亏比': '0.00', + '最终资金': f'{self.initial_capital:.2f}', '月盈利≥1000U的月数': 0, + '月均盈利(U)': '0.00', + } + + +def print_metrics(metrics: dict, title: str = "回测结果"): + """打印绩效指标""" + logger.info(f"\n{'='*50}") + logger.info(f" {title}") + logger.info(f"{'='*50}") + for k, v in metrics.items(): + logger.info(f" {k:>12}: {v}") + logger.info(f"{'='*50}") diff --git a/strategy/compare.py b/strategy/compare.py new file mode 100644 index 0000000..bdc5795 --- /dev/null +++ b/strategy/compare.py @@ -0,0 +1,222 @@ +""" +方案对比评估 — 方案A(统计筛选) vs 方案B(AI模型) 并排对比 + 报告输出 +""" +import pandas as pd +import numpy as np +import matplotlib +matplotlib.use('Agg') # 非交互式后端 +import matplotlib.pyplot as plt +from matplotlib import font_manager +from pathlib import Path +from loguru import logger + +# 设置中文字体 +_zh_font = None +for fname in ['PingFang SC', 'Heiti SC', 'STHeiti', 'SimHei', 'Microsoft YaHei', 'WenQuanYi Micro Hei']: + try: + _zh_font = font_manager.FontProperties(family=fname) + # 验证字体存在 + font_manager.findfont(_zh_font, fallback_to_default=False) + plt.rcParams['font.sans-serif'] = [fname, 'DejaVu Sans'] + plt.rcParams['axes.unicode_minus'] = False + break + except Exception: + _zh_font = None + continue + +from .config import PRIMARY_PERIOD, PROJECT_ROOT +from .stat_strategy import StatStrategy +from .ai_strategy import AIStrategy +from .backtest import print_metrics + + +REPORT_DIR = PROJECT_ROOT / 'reports' + + +def compare_strategies(period: int = None, start_date: str = None, end_date: str = None, + save_plot: bool = True) -> dict: + """ + 运行两种方案并对比 + :return: {'stat': result_a, 'lgb': result_b, 'xgb': result_c, 'comparison': DataFrame} + """ + if period is None: + period = PRIMARY_PERIOD + + logger.info("=" * 70) + logger.info(" 开始策略对比评估") + logger.info("=" * 70) + + results = {} + + # 方案A:统计筛选 + logger.info("\n>>> 运行方案A: 统计筛选策略") + stat = StatStrategy() + results['stat'] = stat.run(period, start_date, end_date) + + # 方案B-1:LightGBM + logger.info("\n>>> 运行方案B-1: LightGBM AI策略") + lgb_strategy = AIStrategy(model_type='lightgbm') + results['lgb'] = lgb_strategy.run(period, start_date, end_date) + + # 方案B-2:XGBoost + logger.info("\n>>> 运行方案B-2: XGBoost AI策略") + xgb_strategy = AIStrategy(model_type='xgboost') + results['xgb'] = xgb_strategy.run(period, start_date, end_date) + + # 对比表格 + comparison = _build_comparison_table(results) + results['comparison'] = comparison + + # 打印对比 + logger.info("\n" + "=" * 70) + logger.info(" 策略对比总结") + logger.info("=" * 70) + logger.info(f"\n{comparison.to_string()}") + + # 每月盈利(U) + _log_monthly_pnl(results) + + # 保存图表 + if save_plot: + _save_equity_plot(results) + + return results + + +def _build_comparison_table(results: dict) -> pd.DataFrame: + """构建对比表格""" + rows = {} + name_map = { + 'stat': '方案A: 统计筛选', + 'lgb': '方案B-1: LightGBM', + 'xgb': '方案B-2: XGBoost', + } + + for key, name in name_map.items(): + if key in results and 'metrics' in results[key]: + rows[name] = results[key]['metrics'] + + if not rows: + return pd.DataFrame() + + df = pd.DataFrame(rows).T + return df + + +def _log_monthly_pnl(results: dict): + """打印各策略每月盈利(USDT)""" + name_map = { + 'stat': '方案A', + 'lgb': 'LightGBM', + 'xgb': 'XGBoost', + } + cols = [] + for key, name in name_map.items(): + if key not in results or results[key].get('monthly_pnl') is None: + continue + s = results[key]['monthly_pnl'] + if s is None or s.empty: + continue + s = s.astype(float).round(2) + s.name = name + cols.append(s) + if not cols: + return + monthly_df = pd.concat(cols, axis=1) + monthly_df = monthly_df.fillna(0) + logger.info("\n" + "-" * 70) + logger.info(" 每月盈利 (USDT)") + logger.info("-" * 70) + logger.info(f"\n{monthly_df.to_string()}") + logger.info("-" * 70) + + +def _save_equity_plot(results: dict): + """保存权益曲线对比图""" + REPORT_DIR.mkdir(parents=True, exist_ok=True) + + fig, axes = plt.subplots(2, 1, figsize=(14, 10)) + + # 上图:权益曲线 + ax1 = axes[0] + name_map = { + 'stat': '方案A: 统计筛选', + 'lgb': '方案B-1: LightGBM', + 'xgb': '方案B-2: XGBoost', + } + colors = {'stat': '#2196F3', 'lgb': '#4CAF50', 'xgb': '#FF9800'} + + for key, name in name_map.items(): + if key in results and 'equity_curve' in results[key]: + eq = results[key]['equity_curve'] + if not eq.empty: + ax1.plot(eq.index, eq.values, label=name, color=colors.get(key, 'gray'), linewidth=1) + + ax1.set_title('权益曲线对比', fontsize=14) + ax1.set_ylabel('资金 (USDT)') + ax1.legend() + ax1.grid(True, alpha=0.3) + + # 下图:回撤曲线 + ax2 = axes[1] + for key, name in name_map.items(): + if key in results and 'equity_curve' in results[key]: + eq = results[key]['equity_curve'] + if not eq.empty: + cummax = eq.cummax() + drawdown = (eq - cummax) / cummax * 100 + ax2.fill_between(drawdown.index, drawdown.values, 0, + alpha=0.3, label=name, color=colors.get(key, 'gray')) + + ax2.set_title('回撤对比', fontsize=14) + ax2.set_ylabel('回撤 (%)') + ax2.legend() + ax2.grid(True, alpha=0.3) + + plt.tight_layout() + plot_path = REPORT_DIR / 'strategy_comparison.png' + plt.savefig(str(plot_path), dpi=150) + plt.close() + logger.info(f"对比图表已保存: {plot_path}") + + +def run_full_comparison(period: int = None, start_date: str = None, end_date: str = None, save_plot: bool = True): + """完整对比入口(可直接调用)""" + results = compare_strategies(period, start_date, end_date, save_plot=save_plot) + + # 推荐最优方案 + best_key = None + best_return = -float('inf') + + for key in ['stat', 'lgb', 'xgb']: + if key in results and 'metrics' in results[key]: + ret_str = results[key]['metrics'].get('总收益率', '0%') + ret_val = float(ret_str.strip('%')) / 100 + if ret_val > best_return: + best_return = ret_val + best_key = key + + name_map = {'stat': '方案A: 统计筛选', 'lgb': '方案B-1: LightGBM', 'xgb': '方案B-2: XGBoost'} + if best_key: + logger.info(f"\n{'='*50}") + logger.info(f" 推荐方案: {name_map.get(best_key, best_key)}") + logger.info(f" 总收益率: {best_return:.2%}") + logger.info(f"{'='*50}") + + return results + + +if __name__ == '__main__': + import argparse + p = argparse.ArgumentParser(description='运行策略对比:方案A(统计) vs 方案B(LightGBM/XGBoost)') + p.add_argument('--period', type=int, default=None, help='K线周期分钟') + p.add_argument('--start', type=str, default=None, help='开始日期,如 2024-01-01') + p.add_argument('--end', type=str, default=None, help='结束日期,如 2024-12-31') + p.add_argument('--no-plot', action='store_true', help='不保存权益/回撤图') + args = p.parse_args() + run_full_comparison( + period=args.period, + start_date=args.start, + end_date=args.end, + save_plot=not args.no_plot, + ) diff --git a/strategy/config.py b/strategy/config.py new file mode 100644 index 0000000..30fb207 --- /dev/null +++ b/strategy/config.py @@ -0,0 +1,151 @@ +""" +全局配置 — 交易参数、指标参数、模型参数 +""" +from pathlib import Path + +# ============ 路径 ============ +PROJECT_ROOT = Path(__file__).parent.parent +DB_PATH = PROJECT_ROOT / 'models' / 'database.db' + +# ============ 交易参数 ============ +TRADE_CONFIG = { + 'symbol': 'ETHUSDT', + 'commission': 0.0006, # 名义手续费 0.06% + 'commission_rebate': 0.90, # 90% 返佣(次日 8 点结算),实付 = commission * (1 - rebate) + 'slippage': 0.0001, # 滑点 0.01% + 'initial_capital': 10000, # 本金 USDT + 'leverage': 100, # 杠杆倍数 + 'position_notional_usd': 500, # 每笔名义 500U(开 100 倍),目标月均收益约 500U + 'max_drawdown_limit': 300, # 最大回撤硬约束:权益从峰值回落超过 300U 则不再开新仓 + # 兼容旧逻辑(若用比例算仓则用此项) + 'position_size': 0.95, +} + +# ============ K线周期 ============ +KLINE_PERIODS = { + 1: '1m', + 3: '3m', + 5: '5m', + 15: '15m', + 30: '30m', + 60: '1h', +} + +# 主周期(用于生成信号) +PRIMARY_PERIOD = 15 # 15分钟 +# 辅助周期(用于多周期融合特征) +AUX_PERIODS = [5, 60] + +# ============ 指标参数 ============ +INDICATOR_PARAMS = { + # 趋势类 + 'sma_windows': [5, 10, 20, 50, 200], + 'ema_windows': [12, 26], + 'macd_fast': 12, + 'macd_slow': 26, + 'macd_signal': 9, + 'adx_window': 14, + 'ichimoku_conversion': 9, + 'ichimoku_base': 26, + 'ichimoku_span_b': 52, + 'trix_window': 15, + 'aroon_window': 25, + 'cci_window': 20, + 'dpo_window': 20, + 'kst_roc1': 10, + 'kst_roc2': 15, + 'kst_roc3': 20, + 'kst_roc4': 30, + 'vortex_window': 14, + + # 动量类 + 'rsi_window': 14, + 'stoch_window': 14, + 'stoch_smooth': 3, + 'williams_window': 14, + 'roc_window': 12, + 'mfi_window': 14, + 'tsi_slow': 25, + 'tsi_fast': 13, + 'uo_short': 7, + 'uo_medium': 14, + 'uo_long': 28, + 'ao_short': 5, + 'ao_long': 34, + 'kama_window': 10, + 'ppo_slow': 26, + 'ppo_fast': 12, + 'stoch_rsi_window': 14, + 'stoch_rsi_smooth': 3, + + # 波动率类 + 'bb_window': 20, + 'bb_std': 2, + 'atr_window': 14, + 'kc_window': 20, + 'dc_window': 20, + + # 成交量类(部分指标需要volume,K线数据可能无volume则跳过) + 'obv_enabled': True, + 'cmf_window': 20, + 'emv_window': 14, + 'fi_window': 13, +} + +# ============ 特征工程参数 ============ +FEATURE_CONFIG = { + 'label_forward_periods': 10, # 未来N根K线用于生成标签 + 'label_threshold': 0.002, # 涨跌阈值(0.2%以内算震荡) + 'lookback_lags': [1, 3, 5], # 滞后特征的lag值 + 'normalize': True, # 是否标准化 +} + +# ============ 模型参数 ============ +MODEL_CONFIG = { + 'walk_forward_train_size': 20000, # Walk-Forward 训练窗口大小 + 'walk_forward_test_size': 2000, # Walk-Forward 测试窗口大小 + 'walk_forward_step': 2000, # 滚动步长 + 'warm_up_months': 12, # 指定回测区间时向前加载的月数,使区间首月即有预测 + + 'lightgbm': { + 'n_estimators': 300, + 'max_depth': 4, + 'learning_rate': 0.03, + 'num_leaves': 15, + 'min_child_samples': 50, + 'subsample': 0.7, + 'colsample_bytree': 0.6, + 'reg_alpha': 1.0, + 'reg_lambda': 1.0, + 'objective': 'multiclass', + 'num_class': 3, + 'verbose': -1, + }, + + 'xgboost': { + 'n_estimators': 300, + 'max_depth': 4, + 'learning_rate': 0.03, + 'subsample': 0.7, + 'colsample_bytree': 0.6, + 'reg_alpha': 1.0, + 'reg_lambda': 1.0, + 'objective': 'multi:softprob', + 'num_class': 3, + 'verbosity': 0, + }, +} + +# ============ 统计筛选参数 ============ +STAT_CONFIG = { + 'top_n_features': 15, # 筛选Top N个指标 + 'correlation_threshold': 0.9, # 去除高相关特征的阈值 + 'grid_search_cv': 3, # 网格搜索交叉验证折数 +} + +# ============ 信号标签映射 ============ +SIGNAL_MAP = { + 0: '观望', + 1: '做多', + 2: '做空', +} diff --git a/strategy/data_loader.py b/strategy/data_loader.py new file mode 100644 index 0000000..b01e09e --- /dev/null +++ b/strategy/data_loader.py @@ -0,0 +1,119 @@ +""" +数据加载器 — 从SQLite加载K线数据为pandas DataFrame +""" +import sqlite3 +import pandas as pd +from loguru import logger +from .config import DB_PATH, KLINE_PERIODS + + +def load_kline(period: int = 15, start_date: str = None, end_date: str = None) -> pd.DataFrame: + """ + 加载指定周期的K线数据 + :param period: K线周期(分钟),如 1, 3, 5, 15, 30, 60 + :param start_date: 起始日期 'YYYY-MM-DD'(可选) + :param end_date: 结束日期 'YYYY-MM-DD'(可选) + :return: DataFrame,列: timestamp, open, high, low, close + """ + suffix = KLINE_PERIODS.get(period) + if suffix is None: + raise ValueError(f"不支持的周期: {period},可选: {list(KLINE_PERIODS.keys())}") + + table_name = f'bitmart_eth_{suffix}' + conn = sqlite3.connect(str(DB_PATH)) + + query = f"SELECT id as timestamp, open, high, low, close FROM {table_name} ORDER BY id" + df = pd.read_sql_query(query, conn) + conn.close() + + if df.empty: + logger.warning(f"[{suffix}] 表中无数据") + return df + + # id 是毫秒时间戳,转为 datetime 索引 + df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms') + df.set_index('datetime', inplace=True) + + # 按日期过滤 + if start_date: + df = df[df.index >= start_date] + if end_date: + df = df[df.index <= end_date] + + logger.info(f"[{suffix}] 加载 {len(df)} 条K线 | {df.index[0]} ~ {df.index[-1]}") + return df + + +def load_multi_period(periods: list = None, start_date: str = None, end_date: str = None) -> dict: + """ + 加载多个周期的K线数据 + :param periods: 周期列表,如 [5, 15, 60],默认全部 + :param start_date: 起始日期 + :param end_date: 结束日期 + :return: {period: DataFrame} 字典 + """ + if periods is None: + periods = list(KLINE_PERIODS.keys()) + + result = {} + for p in periods: + try: + df = load_kline(p, start_date, end_date) + if not df.empty: + result[p] = df + except Exception as e: + logger.error(f"加载 {p}分钟 K线失败: {e}") + + return result + + +def load_trades(start_date: str = None, end_date: str = None, limit: int = None) -> pd.DataFrame: + """ + 加载原始成交记录 + :return: DataFrame,列: id, timestamp, price, volume, side + """ + conn = sqlite3.connect(str(DB_PATH)) + query = "SELECT id, timestamp, price, volume, side FROM bitmart_eth_trades ORDER BY timestamp" + df = pd.read_sql_query(query, conn) + conn.close() + + if df.empty: + logger.warning("成交记录表中无数据") + return df + + df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms') + df.set_index('datetime', inplace=True) + + if start_date: + df = df[df.index >= start_date] + if end_date: + df = df[df.index <= end_date] + if limit: + df = df.head(limit) + + logger.info(f"加载 {len(df)} 条成交记录") + return df + + +def get_available_tables() -> list: + """列出数据库中所有可用的表""" + conn = sqlite3.connect(str(DB_PATH)) + cursor = conn.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name") + tables = [row[0] for row in cursor.fetchall()] + conn.close() + return tables + + +def get_table_stats() -> dict: + """获取各表的数据统计""" + conn = sqlite3.connect(str(DB_PATH)) + tables = get_available_tables() + stats = {} + for table in tables: + try: + count = pd.read_sql_query(f"SELECT COUNT(*) as cnt FROM {table}", conn).iloc[0]['cnt'] + stats[table] = count + except Exception: + stats[table] = 0 + conn.close() + return stats diff --git a/strategy/feature_engine.py b/strategy/feature_engine.py new file mode 100644 index 0000000..433c475 --- /dev/null +++ b/strategy/feature_engine.py @@ -0,0 +1,204 @@ +""" +特征工程 — 标准化、多周期融合、滞后特征、标签生成 +""" +import pandas as pd +import numpy as np +from sklearn.preprocessing import StandardScaler +from loguru import logger + +from .config import FEATURE_CONFIG as FC, PRIMARY_PERIOD, AUX_PERIODS +from .data_loader import load_kline +from .indicators import compute_all_indicators, get_indicator_names + + +def build_features(primary_df: pd.DataFrame, + aux_dfs: dict = None, + has_volume: bool = False) -> pd.DataFrame: + """ + 构建完整特征矩阵 + :param primary_df: 主周期K线 DataFrame + :param aux_dfs: {period: DataFrame} 辅助周期数据(可选) + :param has_volume: 是否有成交量 + :return: 特征矩阵 DataFrame + """ + # 1. 主周期指标 + logger.info("计算主周期指标...") + df = compute_all_indicators(primary_df, has_volume=has_volume) + + # 2. 滞后特征 + logger.info("生成滞后特征...") + indicator_cols = get_indicator_names(has_volume) + existing_cols = [col for col in indicator_cols if col in df.columns] + + lag_frames = [] + for lag in FC['lookback_lags']: + lagged = df[existing_cols].shift(lag).add_suffix(f'_lag{lag}') + lag_frames.append(lagged) + if lag_frames: + df = pd.concat([df] + lag_frames, axis=1) + + # 3. 多周期融合 + if aux_dfs: + aux_frames = [] + for period, aux_df in aux_dfs.items(): + logger.info(f"融合 {period}分钟 辅助周期特征...") + aux_with_ind = compute_all_indicators(aux_df, has_volume=has_volume) + key_indicators = ['rsi', 'macd', 'adx', 'bb_pband', 'atr', 'cci'] + for ind in key_indicators: + if ind in aux_with_ind.columns: + aligned = aux_with_ind[ind].reindex(df.index, method='ffill') + aux_frames.append(aligned.rename(f'{ind}_{period}m')) + if aux_frames: + df = pd.concat([df] + aux_frames, axis=1) + + # 4. 去除全NaN列 + before_cols = len(df.columns) + df.dropna(axis=1, how='all', inplace=True) + after_cols = len(df.columns) + if before_cols != after_cols: + logger.info(f"移除 {before_cols - after_cols} 个全NaN列") + + logger.info(f"特征矩阵: {df.shape[0]} 行 x {df.shape[1]} 列") + return df + + +def generate_labels(df: pd.DataFrame, forward_periods: int = None, + threshold: float = None) -> pd.Series: + """ + 生成交易标签 + :param df: 包含 close 列的 DataFrame + :param forward_periods: 未来N根K线 + :param threshold: 涨跌阈值 + :return: Series,值为 0=观望, 1=做多, 2=做空 + """ + if forward_periods is None: + forward_periods = FC['label_forward_periods'] + if threshold is None: + threshold = FC['label_threshold'] + + future_return = df['close'].shift(-forward_periods) / df['close'] - 1 + + labels = pd.Series(0, index=df.index, name='label') # 默认观望 + labels[future_return > threshold] = 1 # 做多 + labels[future_return < -threshold] = 2 # 做空 + + # 最后 forward_periods 行无法计算标签,设为NaN + labels.iloc[-forward_periods:] = np.nan + + dist = labels.value_counts().to_dict() + logger.info(f"标签分布: 观望={dist.get(0, 0)}, 做多={dist.get(1, 0)}, 做空={dist.get(2, 0)}") + return labels + + +def prepare_dataset(period: int = None, start_date: str = None, end_date: str = None, + has_volume: bool = False) -> tuple: + """ + 一键准备训练数据集 + :return: (X, y, feature_names) — 已去NaN、已标准化 + """ + if period is None: + period = PRIMARY_PERIOD + + # 加载主周期 + primary_df = load_kline(period, start_date, end_date) + if primary_df.empty: + raise ValueError(f"{period}分钟 K线数据为空") + + # 加载辅助周期 + aux_dfs = {} + for aux_p in AUX_PERIODS: + try: + aux_df = load_kline(aux_p, start_date, end_date) + if not aux_df.empty: + aux_dfs[aux_p] = aux_df + except Exception as e: + logger.warning(f"加载 {aux_p}分钟 辅助数据失败: {e}") + + # 构建特征 + df = build_features(primary_df, aux_dfs, has_volume=has_volume) + + # 生成标签 + labels = generate_labels(df) + df = df.copy() + df['label'] = labels + + # 去除NaN行 + df.dropna(inplace=True) + logger.info(f"去NaN后剩余 {len(df)} 行") + + # 分离 X, y + exclude_cols = ['open', 'high', 'low', 'close', 'timestamp', 'label'] + if 'volume' in df.columns: + exclude_cols.append('volume') + + # 排除价格级别特征(会泄露绝对价格信息导致过拟合) + price_level_patterns = [ + 'sma_', 'ema_', 'bb_upper', 'bb_mid', 'bb_lower', + 'kc_upper', 'kc_mid', 'kc_lower', 'dc_upper', 'dc_mid', 'dc_lower', + 'ichimoku_conv', 'ichimoku_base', 'ichimoku_a', 'ichimoku_b', + 'kama', 'vwap', 'obv', 'adi', 'vpt', 'nvi', + 'momentum_3', 'momentum_5', + ] + feature_cols = [] + for c in df.columns: + if c in exclude_cols: + continue + base_name = c.split('_lag')[0] + # 去掉周期后缀 + for suffix in ['_5m', '_60m', '_3m', '_15m', '_30m', '_1m']: + if base_name.endswith(suffix): + base_name = base_name[:-len(suffix)] + break + if any(base_name.startswith(p) or base_name == p.rstrip('_') for p in price_level_patterns): + continue + feature_cols.append(c) + + logger.info(f"排除价格级别特征后剩余 {len(feature_cols)} 个特征") + + X = df[feature_cols].copy() + y = df['label'].astype(int) + + # 标准化 + scaler = None + if FC['normalize']: + scaler = StandardScaler() + X = pd.DataFrame(scaler.fit_transform(X), columns=feature_cols, index=X.index) + logger.info("特征已标准化") + + logger.info(f"最终数据集: X={X.shape}, y={y.shape}, 特征数={len(feature_cols)}") + return X, y, feature_cols, scaler + + +def get_latest_feature_row(period: int = None, feature_cols: list = None, + start_date: str = None, end_date: str = None) -> pd.DataFrame: + """ + 构建特征并返回最后一行的特征矩阵(用于实盘/模拟盘预测)。 + 需传入已保存的 feature_cols,保证与训练时一致。 + :return: 1 行 DataFrame,列为 feature_cols;若缺列则返回空 DataFrame + """ + if period is None: + period = PRIMARY_PERIOD + if not feature_cols: + return pd.DataFrame() + + primary_df = load_kline(period, start_date, end_date) + if primary_df.empty: + return pd.DataFrame() + aux_dfs = {} + for aux_p in AUX_PERIODS: + try: + aux_df = load_kline(aux_p, start_date, end_date) + if not aux_df.empty: + aux_dfs[aux_p] = aux_df + except Exception: + pass + df = build_features(primary_df, aux_dfs, has_volume=False) + labels = generate_labels(df) + df = df.copy() + df['label'] = labels + df.dropna(inplace=True) + missing = [c for c in feature_cols if c not in df.columns] + if missing: + logger.warning(f"get_latest_feature_row: 缺少特征列 {missing[:5]}{'...' if len(missing) > 5 else ''}") + return pd.DataFrame() + return df[feature_cols].iloc[-1:].copy() diff --git a/strategy/indicators.py b/strategy/indicators.py new file mode 100644 index 0000000..3ca8521 --- /dev/null +++ b/strategy/indicators.py @@ -0,0 +1,278 @@ +""" +52个技术指标计算引擎 — 基于 ta 库 +覆盖趋势、动量、波动率、成交量、自定义衍生特征五大类 +""" +import pandas as pd +import numpy as np +import ta +from .config import INDICATOR_PARAMS as P + + +def compute_all_indicators(df: pd.DataFrame, has_volume: bool = False) -> pd.DataFrame: + """ + 计算全部52个技术指标,返回拼接后的DataFrame + :param df: 必须包含 open, high, low, close 列;可选 volume 列 + :param has_volume: 是否有成交量数据 + :return: 原始列 + 52个指标列 + """ + out = df.copy() + o, h, l, c = out['open'], out['high'], out['low'], out['close'] + v = out['volume'] if has_volume and 'volume' in out.columns else None + + # ========== 趋势类 (14) ========== + out = _add_trend(out, o, h, l, c) + + # ========== 动量类 (12) ========== + out = _add_momentum(out, h, l, c, v) + + # ========== 波动率类 (8) ========== + out = _add_volatility(out, h, l, c) + + # ========== 成交量类 (8) ========== + if has_volume and v is not None: + out = _add_volume(out, h, l, c, v) + + # ========== 自定义衍生特征 (10) ========== + out = _add_custom(out, o, h, l, c) + + return out + + +def _add_trend(out, o, h, l, c): + """趋势类指标 (14个特征)""" + # SMA (5个) + for w in P['sma_windows']: + out[f'sma_{w}'] = ta.trend.sma_indicator(c, window=w) + + # EMA (2个) + for w in P['ema_windows']: + out[f'ema_{w}'] = ta.trend.ema_indicator(c, window=w) + + # MACD (3个) + macd = ta.trend.MACD(c, window_slow=P['macd_slow'], window_fast=P['macd_fast'], + window_sign=P['macd_signal']) + out['macd'] = macd.macd() + out['macd_signal'] = macd.macd_signal() + out['macd_hist'] = macd.macd_diff() + + # ADX + DI (3个) + adx = ta.trend.ADXIndicator(h, l, c, window=P['adx_window']) + out['adx'] = adx.adx() + out['di_plus'] = adx.adx_pos() + out['di_minus'] = adx.adx_neg() + + # Ichimoku (4个) + ichi = ta.trend.IchimokuIndicator(h, l, + window1=P['ichimoku_conversion'], + window2=P['ichimoku_base'], + window3=P['ichimoku_span_b']) + out['ichimoku_conv'] = ichi.ichimoku_conversion_line() + out['ichimoku_base'] = ichi.ichimoku_base_line() + out['ichimoku_a'] = ichi.ichimoku_a() + out['ichimoku_b'] = ichi.ichimoku_b() + + # TRIX + out['trix'] = ta.trend.trix(c, window=P['trix_window']) + + # Aroon (2个) + aroon = ta.trend.AroonIndicator(h, l, window=P['aroon_window']) + out['aroon_up'] = aroon.aroon_up() + out['aroon_down'] = aroon.aroon_down() + + # CCI + out['cci'] = ta.trend.cci(h, l, c, window=P['cci_window']) + + # DPO + out['dpo'] = ta.trend.dpo(c, window=P['dpo_window']) + + # KST + kst = ta.trend.KSTIndicator(c, roc1=P['kst_roc1'], roc2=P['kst_roc2'], + roc3=P['kst_roc3'], roc4=P['kst_roc4']) + out['kst'] = kst.kst() + + # Vortex (2个) + vortex = ta.trend.VortexIndicator(h, l, c, window=P['vortex_window']) + out['vortex_pos'] = vortex.vortex_indicator_pos() + out['vortex_neg'] = vortex.vortex_indicator_neg() + + return out + + +def _add_momentum(out, h, l, c, v): + """动量类指标 (12个特征)""" + # RSI + out['rsi'] = ta.momentum.rsi(c, window=P['rsi_window']) + + # Stochastic %K / %D + stoch = ta.momentum.StochasticOscillator(h, l, c, + window=P['stoch_window'], + smooth_window=P['stoch_smooth']) + out['stoch_k'] = stoch.stoch() + out['stoch_d'] = stoch.stoch_signal() + + # Williams %R + out['williams_r'] = ta.momentum.williams_r(h, l, c, lbp=P['williams_window']) + + # ROC + out['roc'] = ta.momentum.roc(c, window=P['roc_window']) + + # MFI(需要volume) + if v is not None: + out['mfi'] = ta.volume.money_flow_index(h, l, c, v, window=P['mfi_window']) + + # TSI + out['tsi'] = ta.momentum.tsi(c, window_slow=P['tsi_slow'], window_fast=P['tsi_fast']) + + # Ultimate Oscillator + out['uo'] = ta.momentum.ultimate_oscillator(h, l, c, + window1=P['uo_short'], + window2=P['uo_medium'], + window3=P['uo_long']) + + # Awesome Oscillator + out['ao'] = ta.momentum.awesome_oscillator(h, l, + window1=P['ao_short'], + window2=P['ao_long']) + + # KAMA + out['kama'] = ta.momentum.kama(c, window=P['kama_window']) + + # PPO + out['ppo'] = ta.momentum.ppo(c, window_slow=P['ppo_slow'], window_fast=P['ppo_fast']) + + # Stochastic RSI %K / %D + stoch_rsi = ta.momentum.StochRSIIndicator(c, + window=P['stoch_rsi_window'], + smooth1=P['stoch_rsi_smooth'], + smooth2=P['stoch_rsi_smooth']) + out['stoch_rsi_k'] = stoch_rsi.stochrsi_k() + out['stoch_rsi_d'] = stoch_rsi.stochrsi_d() + + return out + + +def _add_volatility(out, h, l, c): + """波动率类指标 (8个特征 — 含子指标共12列)""" + # Bollinger Bands (5个) + bb = ta.volatility.BollingerBands(c, window=P['bb_window'], window_dev=P['bb_std']) + out['bb_upper'] = bb.bollinger_hband() + out['bb_mid'] = bb.bollinger_mavg() + out['bb_lower'] = bb.bollinger_lband() + out['bb_width'] = bb.bollinger_wband() + out['bb_pband'] = bb.bollinger_pband() + + # ATR + out['atr'] = ta.volatility.average_true_range(h, l, c, window=P['atr_window']) + + # Keltner Channel (3个) + kc = ta.volatility.KeltnerChannel(h, l, c, window=P['kc_window']) + out['kc_upper'] = kc.keltner_channel_hband() + out['kc_mid'] = kc.keltner_channel_mband() + out['kc_lower'] = kc.keltner_channel_lband() + + # Donchian Channel (3个) + dc = ta.volatility.DonchianChannel(h, l, c, window=P['dc_window']) + out['dc_upper'] = dc.donchian_channel_hband() + out['dc_mid'] = dc.donchian_channel_mband() + out['dc_lower'] = dc.donchian_channel_lband() + + return out + + +def _add_volume(out, h, l, c, v): + """成交量类指标 (8个特征)""" + # OBV + out['obv'] = ta.volume.on_balance_volume(c, v) + + # VWAP + out['vwap'] = ta.volume.volume_weighted_average_price(h, l, c, v) + + # CMF + out['cmf'] = ta.volume.chaikin_money_flow(h, l, c, v, window=P['cmf_window']) + + # ADI (Accumulation/Distribution Index) + out['adi'] = ta.volume.acc_dist_index(h, l, c, v) + + # EMV (Ease of Movement) + out['emv'] = ta.volume.ease_of_movement(h, l, v, window=P['emv_window']) + + # Force Index + out['fi'] = ta.volume.force_index(c, v, window=P['fi_window']) + + # VPT (Volume Price Trend) + out['vpt'] = ta.volume.volume_price_trend(c, v) + + # NVI (Negative Volume Index) + out['nvi'] = ta.volume.negative_volume_index(c, v) + + return out + + +def _add_custom(out, o, h, l, c): + """自定义衍生特征 (10个)""" + # 价格变化率 + out['price_change_pct'] = c.pct_change() + + # 振幅(High-Low范围 / Close) + out['high_low_range'] = (h - l) / c + + # 实体比率(|Close-Open| / (High-Low)) + body = (c - o).abs() + hl_range = (h - l).replace(0, np.nan) + out['body_ratio'] = body / hl_range + + # 上影线比率 + upper_shadow = h - pd.concat([o, c], axis=1).max(axis=1) + out['upper_shadow'] = upper_shadow / hl_range + + # 下影线比率 + lower_shadow = pd.concat([o, c], axis=1).min(axis=1) - l + out['lower_shadow'] = lower_shadow / hl_range + + # 波动率比率(ATR / Close 的滚动比值) + atr = ta.volatility.average_true_range(h, l, c, window=14) + out['volatility_ratio'] = atr / c + + # Close / SMA20 比率 + sma20 = ta.trend.sma_indicator(c, window=20) + out['close_sma20_ratio'] = c / sma20.replace(0, np.nan) + + # Close / EMA12 比率 + ema12 = ta.trend.ema_indicator(c, window=12) + out['close_ema12_ratio'] = c / ema12.replace(0, np.nan) + + # 动量 3周期 + out['momentum_3'] = c - c.shift(3) + + # 动量 5周期 + out['momentum_5'] = c - c.shift(5) + + return out + + +def get_indicator_names(has_volume: bool = False) -> list: + """返回所有指标列名""" + names = [] + # 趋势 + for w in P['sma_windows']: + names.append(f'sma_{w}') + for w in P['ema_windows']: + names.append(f'ema_{w}') + names += ['macd', 'macd_signal', 'macd_hist', 'adx', 'di_plus', 'di_minus'] + names += ['ichimoku_conv', 'ichimoku_base', 'ichimoku_a', 'ichimoku_b'] + names += ['trix', 'aroon_up', 'aroon_down', 'cci', 'dpo', 'kst', 'vortex_pos', 'vortex_neg'] + # 动量 + names += ['rsi', 'stoch_k', 'stoch_d', 'williams_r', 'roc', 'tsi', 'uo', 'ao', 'kama', 'ppo', + 'stoch_rsi_k', 'stoch_rsi_d'] + if has_volume: + names.append('mfi') + # 波动率 + names += ['bb_upper', 'bb_mid', 'bb_lower', 'bb_width', 'bb_pband', 'atr', + 'kc_upper', 'kc_mid', 'kc_lower', 'dc_upper', 'dc_mid', 'dc_lower'] + # 成交量 + if has_volume: + names += ['obv', 'vwap', 'cmf', 'adi', 'emv', 'fi', 'vpt', 'nvi'] + # 自定义 + names += ['price_change_pct', 'high_low_range', 'body_ratio', 'upper_shadow', 'lower_shadow', + 'volatility_ratio', 'close_sma20_ratio', 'close_ema12_ratio', 'momentum_3', 'momentum_5'] + return names diff --git a/strategy/stat_strategy.py b/strategy/stat_strategy.py new file mode 100644 index 0000000..05528b1 --- /dev/null +++ b/strategy/stat_strategy.py @@ -0,0 +1,256 @@ +""" +方案A:统计筛选 + 规则组合策略 +1. 从52个指标中用统计方法筛选最有效的指标 +2. 用经典规则组合生成交易信号 +3. 网格搜索优化参数 +""" +import pandas as pd +import numpy as np +from sklearn.ensemble import RandomForestClassifier +from sklearn.feature_selection import mutual_info_classif +from loguru import logger + +from .config import STAT_CONFIG as SC, PRIMARY_PERIOD, AUX_PERIODS +from .feature_engine import prepare_dataset +from .backtest import BacktestEngine, print_metrics + + +class StatStrategy: + """统计筛选策略""" + + def __init__(self): + self.top_features = [] + self.feature_scores = {} + self.best_params = {} + + def select_features(self, X: pd.DataFrame, y: pd.Series) -> list: + """ + 用多种统计方法筛选有效指标 + :return: Top N 特征名列表 + """ + logger.info("=" * 50) + logger.info("开始特征筛选...") + scores = {} + + # 1. 皮尔逊相关系数 + logger.info("计算皮尔逊相关系数...") + corr_scores = X.corrwith(y).abs().fillna(0) + for col in X.columns: + scores[col] = scores.get(col, 0) + corr_scores.get(col, 0) + + # 2. 互信息 + logger.info("计算互信息...") + mi = mutual_info_classif(X.fillna(0), y, random_state=42) + mi_series = pd.Series(mi, index=X.columns) + mi_norm = mi_series / mi_series.max() if mi_series.max() > 0 else mi_series + for col in X.columns: + scores[col] = scores.get(col, 0) + mi_norm.get(col, 0) + + # 3. 随机森林特征重要性 + logger.info("训练随机森林评估特征重要性...") + rf = RandomForestClassifier(n_estimators=200, max_depth=8, random_state=42, n_jobs=-1) + rf.fit(X.fillna(0), y) + rf_imp = pd.Series(rf.feature_importances_, index=X.columns) + rf_norm = rf_imp / rf_imp.max() if rf_imp.max() > 0 else rf_imp + for col in X.columns: + scores[col] = scores.get(col, 0) + rf_norm.get(col, 0) + + # 综合排名 + score_series = pd.Series(scores).sort_values(ascending=False) + self.feature_scores = score_series.to_dict() + + # 去除高相关特征 + top_candidates = score_series.head(SC['top_n_features'] * 2).index.tolist() + selected = self._remove_correlated(X[top_candidates], SC['correlation_threshold']) + self.top_features = selected[:SC['top_n_features']] + + logger.info(f"筛选出 Top {len(self.top_features)} 特征:") + for i, feat in enumerate(self.top_features): + logger.info(f" {i+1}. {feat} (综合得分: {score_series[feat]:.4f})") + + return self.top_features + + def _remove_correlated(self, X: pd.DataFrame, threshold: float) -> list: + """去除高度相关的冗余特征""" + corr_matrix = X.corr().abs() + selected = list(X.columns) + to_remove = set() + + for i in range(len(selected)): + if selected[i] in to_remove: + continue + for j in range(i + 1, len(selected)): + if selected[j] in to_remove: + continue + if corr_matrix.loc[selected[i], selected[j]] > threshold: + to_remove.add(selected[j]) + + result = [c for c in selected if c not in to_remove] + if to_remove: + logger.info(f"移除 {len(to_remove)} 个高相关冗余特征") + return result + + def generate_signals(self, df: pd.DataFrame) -> pd.Series: + """ + 基于筛选出的指标,用规则组合生成交易信号 + :param df: 包含指标列的 DataFrame(原始值,非标准化) + :return: 信号 Series (0=观望, 1=做多, 2=做空) + """ + signals = pd.Series(0, index=df.index) + long_score = pd.Series(0.0, index=df.index) + short_score = pd.Series(0.0, index=df.index) + matched = 0 + + for feat in self.top_features: + if feat not in df.columns: + continue + + col = df[feat] + base = feat.split('_lag')[0] # 去掉 _lagN 后缀 + # 去掉辅助周期后缀 _5m / _60m + for suffix in ['_5m', '_60m', '_3m', '_15m', '_30m', '_1m']: + if base.endswith(suffix): + base = base[:-len(suffix)] + break + + if 'rsi' in base: + long_score += (col < 35).astype(float) + short_score += (col > 65).astype(float) + matched += 1 + elif base == 'macd_hist': + long_score += (col > 0).astype(float) + short_score += (col < 0).astype(float) + matched += 1 + elif base == 'macd': + long_score += (col > 0).astype(float) + short_score += (col < 0).astype(float) + matched += 1 + elif 'bb_pband' in base: + long_score += (col < 0.2).astype(float) + short_score += (col > 0.8).astype(float) + matched += 1 + elif 'adx' in base: + long_score += (col > 25).astype(float) + short_score += (col > 25).astype(float) + matched += 1 + elif 'cci' in base: + long_score += (col < -100).astype(float) + short_score += (col > 100).astype(float) + matched += 1 + elif 'stoch_k' in base or 'stoch_rsi_k' in base: + long_score += (col < 25).astype(float) + short_score += (col > 75).astype(float) + matched += 1 + elif 'williams_r' in base: + long_score += (col < -80).astype(float) + short_score += (col > -20).astype(float) + matched += 1 + elif 'ao' in base or 'tsi' in base or 'roc' in base or 'ppo' in base: + long_score += (col > 0).astype(float) + short_score += (col < 0).astype(float) + matched += 1 + elif 'atr' in base or 'volatility_ratio' in base: + # 波动率类:高波动时趋势更强,用均值分界 + median = col.rolling(200, min_periods=50).median() + long_score += (col > median).astype(float) * 0.5 + short_score += (col > median).astype(float) * 0.5 + matched += 1 + elif 'high_low_range' in base or 'body_ratio' in base: + median = col.rolling(200, min_periods=50).median() + long_score += (col > median).astype(float) * 0.3 + short_score += (col > median).astype(float) * 0.3 + matched += 1 + elif 'bb_width' in base: + # 布林带宽度收窄后扩张 = 突破信号,结合价格方向 + median = col.rolling(200, min_periods=50).median() + expanding = col > col.shift(1) # 宽度在扩张 + was_narrow = col.shift(1) < median # 之前是收窄的 + breakout = expanding & was_narrow + if 'close' in df.columns: + price_up = df['close'] > df['close'].shift(1) + long_score += (breakout & price_up).astype(float) + short_score += (breakout & ~price_up).astype(float) + else: + long_score += breakout.astype(float) * 0.5 + short_score += breakout.astype(float) * 0.5 + matched += 1 + elif 'close_sma20_ratio' in base or 'close_ema12_ratio' in base: + # 价格在均线上方=多头,下方=空头 + long_score += (col > 1.0).astype(float) + short_score += (col < 1.0).astype(float) + matched += 1 + elif 'ichimoku' in base: + if 'close' in df.columns: + long_score += (df['close'] > col).astype(float) + short_score += (df['close'] < col).astype(float) + matched += 1 + elif 'momentum' in base or 'price_change' in base: + long_score += (col > 0).astype(float) + short_score += (col < 0).astype(float) + matched += 1 + + logger.info(f"规则匹配: {matched}/{len(self.top_features)} 个特征有对应规则") + + # 阈值:至少50%的匹配特征同时确认(更严格) + threshold = max(3, matched * 0.5) + logger.info(f"信号阈值: {threshold:.1f} (需要至少这么多指标同时确认)") + signals[long_score >= threshold] = 1 + signals[short_score >= threshold] = 2 + # 多空同时满足时取更强的 + both = (long_score >= threshold) & (short_score >= threshold) + signals[both & (long_score > short_score)] = 1 + signals[both & (short_score > long_score)] = 2 + signals[both & (long_score == short_score)] = 0 + + dist = signals.value_counts().to_dict() + logger.info(f"规则信号分布: 观望={dist.get(0, 0)}, 做多={dist.get(1, 0)}, 做空={dist.get(2, 0)}") + return signals + + def run(self, period: int = None, start_date: str = None, end_date: str = None) -> dict: + """ + 完整运行方案A + :return: 回测结果 + """ + if period is None: + period = PRIMARY_PERIOD + + logger.info("=" * 60) + logger.info("方案A:统计筛选 + 规则组合策略") + logger.info("=" * 60) + + # 1. 准备数据(标准化版本,用于特征筛选) + X, y, feature_names, _ = prepare_dataset(period, start_date, end_date) + + # 2. 筛选特征 + self.select_features(X, y) + + # 3. 构建完整特征矩阵(原始值,非标准化,用于规则判断) + from .data_loader import load_kline, load_multi_period + from .feature_engine import build_features + primary_df = load_kline(period, start_date, end_date) + aux_dfs = {} + for aux_p in AUX_PERIODS: + try: + aux_df = load_kline(aux_p, start_date, end_date) + if not aux_df.empty: + aux_dfs[aux_p] = aux_df + except Exception: + pass + df = build_features(primary_df, aux_dfs) + df.dropna(inplace=True) + + # 4. 生成信号 + signals = self.generate_signals(df) + + # 5. 回测 + engine = BacktestEngine() + result = engine.run(df['close'], signals) + + print_metrics(result['metrics'], "方案A: 统计筛选策略") + return result + + +def run_stat_strategy(period: int = None, start_date: str = None, end_date: str = None) -> dict: + """方案A快捷入口""" + strategy = StatStrategy() + return strategy.run(period, start_date, end_date) diff --git a/test.py b/test.py new file mode 100644 index 0000000..842179d --- /dev/null +++ b/test.py @@ -0,0 +1,2 @@ +from strategy.compare import run_full_comparison +results = run_full_comparison(period=15) \ No newline at end of file diff --git a/四分之一,五分钟,反手条件充足.py b/四分之一,五分钟,反手条件充足.py new file mode 100644 index 0000000..66c5888 --- /dev/null +++ b/四分之一,五分钟,反手条件充足.py @@ -0,0 +1,694 @@ +import sys +import time +from pathlib import Path + +from tqdm import tqdm +from loguru import logger +from bit_tools import openBrowser +from DrissionPage import ChromiumPage +from DrissionPage import ChromiumOptions + +from bitmart.api_contract import APIContract + +# 方案B:从 strategy 模块获取实盘信号(需先运行 AI 策略训练保存模型,并保持 models/database.db 有最新 15m/5m/1h K 线,例如运行 抓取多周期K线.py) +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from strategy.ai_strategy import get_live_signal + + +class BitmartFuturesTransaction: + def __init__(self, bit_id): + + self.page: ChromiumPage | None = None + + self.api_key = "a0fb7b98464fd9bcce67e7c519d58ec10d0c38a8" + self.secret_key = "4eaeba78e77aeaab1c2027f846a276d164f264a44c2c1bb1c5f3be50c8de1ca5" + self.memo = "合约交易" + + self.contract_symbol = "ETHUSDT" + + self.contractAPI = APIContract(self.api_key, self.secret_key, self.memo, timeout=(5, 15)) + + self.start = 0 # 持仓状态: -1 空, 0 无, 1 多 + + self.pbar = tqdm(total=30, desc="等待K线", ncols=80) # 可选:用于长时间等待时展示进度 + + self.last_kline_time = None # 上一次出信号的 15 分钟 K 线 id(方案B 每根 15m 只出一次信号) + + # 反手频率控制 + self.reverse_cooldown_seconds = 1.5 * 60 # 反手冷却时间(秒) + self.reverse_min_move_pct = 0.05 # 反手最小价差过滤(百分比) + self.last_reverse_time = None # 上次反手时间 + + # 开仓频率控制 + self.open_cooldown_seconds = 60 # 开仓冷却时间(秒),两次开仓至少间隔此时长 + self.last_open_time = None # 上次开仓时间 + self.last_open_kline_id = None # 上次开仓所在 K 线 id,同一根 K 线只允许开仓一次 + + self.leverage = "100" # 高杠杆(全仓模式下可开更大仓位) + self.open_type = "cross" # 全仓模式 + self.risk_percent = 0 # 未使用;若启用则可为每次开仓占可用余额的百分比 + self.take_profit_usd = 5 # 仓位盈利达到此金额(美元)时平仓止盈 + self.stop_loss_usd = -3 # 固定止损:亏损达到 3 美元平仓 + self.trailing_activation_usd = 2 # 盈利达到此金额后启动移动止损 + self.trailing_distance_usd = 1.5 # 从最高盈利回撤此金额则平仓 + self.max_unrealized_pnl_seen = None # 持仓期间见过的最大盈利(用于移动止损) + + self.open_avg_price = None # 开仓价格 + self.current_amount = None # 持仓量 + + self.bit_id = bit_id + self.default_order_size = 25 # 开仓/反手张数,统一在此修改 + + # 策略相关变量 + self.prev_kline = None # 上一根K线 + self.current_kline = None # 当前K线 + self.prev_entity = None # 上一根K线实体大小 + self.current_open = None # 当前K线开盘价 + + def get_klines(self): + """获取最近2根K线(当前K线和上一根K线)""" + try: + end_time = int(time.time()) + # 获取足够多的条目确保有最新的K线 + response = self.contractAPI.get_kline( + contract_symbol=self.contract_symbol, + step=5, # 5分钟 + start_time=end_time - 3600 * 3, # 取最近3小时 + end_time=end_time + )[0]["data"] + + # 每根: [timestamp, open, high, low, close, volume] + formatted = [] + for k in response: + formatted.append({ + 'id': int(k["timestamp"]), + 'open': float(k["open_price"]), + 'high': float(k["high_price"]), + 'low': float(k["low_price"]), + 'close': float(k["close_price"]) + }) + formatted.sort(key=lambda x: x['id']) + + # 返回最近2根K线:倒数第二根(上一根)和最后一根(当前) + if len(formatted) >= 2: + return formatted[-2], formatted[-1] + return None, None + except Exception as e: + logger.error(f"获取K线异常: {e}") + self.ding(text="获取K线异常", error=True) + return None, None + + def get_current_price(self): + """获取当前最新价格""" + try: + end_time = int(time.time()) + response = self.contractAPI.get_kline( + contract_symbol=self.contract_symbol, + step=1, # 1分钟 + start_time=end_time - 3600 * 1, # 取最近1小时 + end_time=end_time + )[0] + if response['code'] == 1000: + return float(response['data'][-1]["close_price"]) + return None + except Exception as e: + logger.error(f"获取价格异常: {e}") + return None + + def get_available_balance(self): + """获取合约账户可用USDT余额""" + try: + response = self.contractAPI.get_assets_detail()[0] + if response['code'] == 1000: + data = response['data'] + if isinstance(data, dict): + return float(data.get('available_balance', 0)) + elif isinstance(data, list): + for asset in data: + if asset.get('currency') == 'USDT': + return float(asset.get('available_balance', 0)) + return None + except Exception as e: + logger.error(f"余额查询异常: {e}") + return None + + def get_position_status(self): + """获取当前持仓方向""" + try: + response = self.contractAPI.get_position(contract_symbol=self.contract_symbol)[0] + if response['code'] == 1000: + positions = response['data'] + if not positions: + self.start = 0 + self.open_avg_price = None + self.current_amount = None + self.unrealized_pnl = None + return True + pos = positions[0] + self.start = 1 if pos['position_type'] == 1 else -1 + self.open_avg_price = float(pos['open_avg_price']) + self.current_amount = float(pos['current_amount']) + self.position_cross = pos["position_cross"] + # 直接从API获取未实现盈亏(Bitmart返回的是 unrealized_value 字段) + self.unrealized_pnl = float(pos.get('unrealized_value', 0)) + logger.debug(f"持仓详情: 方向={self.start}, 开仓均价={self.open_avg_price}, " + f"持仓量={self.current_amount}, 未实现盈亏={self.unrealized_pnl:.2f}") + return True + else: + return False + except Exception as e: + logger.error(f"持仓查询异常: {e}") + return False + + def get_unrealized_pnl_usd(self): + """ + 获取当前持仓未实现盈亏(美元),直接使用API返回值 + """ + if self.start == 0 or self.unrealized_pnl is None: + return None + return self.unrealized_pnl + + def set_leverage(self): + """程序启动时设置全仓 + 高杠杆""" + try: + response = self.contractAPI.post_submit_leverage( + contract_symbol=self.contract_symbol, + leverage=self.leverage, + open_type=self.open_type + )[0] + if response['code'] == 1000: + logger.success(f"全仓模式 + {self.leverage}x 杠杆设置成功") + return True + else: + logger.error(f"杠杆设置失败: {response}") + return False + except Exception as e: + logger.error(f"设置杠杆异常: {e}") + return False + + def openBrowser(self): + """打开 TGE 对应浏览器实例""" + try: + bit_port = openBrowser(id=self.bit_id) + co = ChromiumOptions() + co.set_local_port(port=bit_port) + self.page = ChromiumPage(addr_or_opts=co) + return True + except: + return False + + def click_safe(self, xpath, sleep=0.5): + """安全点击""" + try: + ele = self.page.ele(xpath) + if not ele: + return False + # ele.scroll.to_see(center=True) + # time.sleep(sleep) + ele.click(by_js=True) + return True + except: + return False + + def 平仓(self): + """平仓操作""" + self.click_safe('x://span[normalize-space(text()) ="市价"]') + + def 开单(self, marketPriceLongOrder=0, limitPriceShortOrder=0, size=None, price=None): + """ + marketPriceLongOrder 市价做多或者做空,1是做多,-1是做空 + limitPriceShortOrder 限价做多或者做空 + """ + if marketPriceLongOrder == -1: + # self.click_safe('x://button[normalize-space(text()) ="市价"]') + # self.page.ele('x://*[@id="size_0"]').input(vals=size, clear=True) + self.click_safe('x://span[normalize-space(text()) ="卖出/做空"]') + elif marketPriceLongOrder == 1: + # self.click_safe('x://button[normalize-space(text()) ="市价"]') + # self.page.ele('x://*[@id="size_0"]').input(vals=size, clear=True) + self.click_safe('x://span[normalize-space(text()) ="买入/做多"]') + + if limitPriceShortOrder == -1: + self.click_safe('x://button[normalize-space(text()) ="限价"]') + self.page.ele('x://*[@id="price_0"]').input(vals=price, clear=True) + time.sleep(1) + self.page.ele('x://*[@id="size_0"]').input(1) + self.click_safe('x://span[normalize-space(text()) ="卖出/做空"]') + elif limitPriceShortOrder == 1: + self.click_safe('x://button[normalize-space(text()) ="限价"]') + self.page.ele('x://*[@id="price_0"]').input(vals=price, clear=True) + time.sleep(1) + self.page.ele('x://*[@id="size_0"]').input(1) + self.click_safe('x://span[normalize-space(text()) ="买入/做多"]') + + def ding(self, text, error=False): + """日志通知""" + if error: + logger.error(text) + else: + logger.info(text) + + def calculate_entity(self, kline): + """计算K线实体大小(绝对值)""" + return abs(kline['close'] - kline['open']) + + def calculate_upper_shadow(self, kline): + """计算上阴线(上影线)涨幅百分比""" + # 上阴线 = (最高价 - max(开盘价, 收盘价)) / max(开盘价, 收盘价) + body_top = max(kline['open'], kline['close']) + if body_top == 0: + return 0 + return (kline['high'] - body_top) / body_top * 100 + + def calculate_lower_shadow(self, kline): + """计算下阴线(下影线)跌幅百分比""" + # 下阴线 = (min(开盘价, 收盘价) - 最低价) / min(开盘价, 收盘价) + body_bottom = min(kline['open'], kline['close']) + if body_bottom == 0: + return 0 + return (body_bottom - kline['low']) / body_bottom * 100 + + def get_entity_edge(self, kline): + """获取K线实体边(收盘价或开盘价,取决于是阳线还是阴线)""" + # 阳线(收盘>开盘):实体上边=收盘价,实体下边=开盘价 + # 阴线(收盘<开盘):实体上边=开盘价,实体下边=收盘价 + return { + 'upper': max(kline['open'], kline['close']), # 实体上边 + 'lower': min(kline['open'], kline['close']) # 实体下边 + } + + def check_signal(self, current_price, prev_kline, current_kline): + """ + 检查交易信号 + 返回: ('long', trigger_price) / ('short', trigger_price) / None + """ + # 计算上一根K线实体 + prev_entity = self.calculate_entity(prev_kline) + + # 实体过小不交易(实体 < 0.1) + if prev_entity < 0.1: + logger.info(f"上一根K线实体过小: {prev_entity:.4f},跳过信号检测") + return None + + # 获取上一根K线的实体上下边 + prev_entity_edge = self.get_entity_edge(prev_kline) + prev_entity_upper = prev_entity_edge['upper'] # 实体上边 + prev_entity_lower = prev_entity_edge['lower'] # 实体下边 + + # 优化:以下两种情况以当前这根的开盘价作为计算基准 + # 1) 上一根阳线 且 当前开盘价 > 上一根收盘价(跳空高开) + # 2) 上一根阴线 且 当前开盘价 < 上一根收盘价(跳空低开) + prev_is_bullish_for_calc = prev_kline['close'] > prev_kline['open'] + prev_is_bearish_for_calc = prev_kline['close'] < prev_kline['open'] + current_open_above_prev_close = current_kline['open'] > prev_kline['close'] + current_open_below_prev_close = current_kline['open'] < prev_kline['close'] + use_current_open_as_base = (prev_is_bullish_for_calc and current_open_above_prev_close) or (prev_is_bearish_for_calc and current_open_below_prev_close) + + if use_current_open_as_base: + # 以当前K线开盘价为基准计算(跳空时用当前开盘价参与计算) + calc_lower = current_kline['open'] + calc_upper = current_kline['open'] # 同一基准,上下四分之一对称 + long_trigger = calc_lower + prev_entity / 4 + short_trigger = calc_upper - prev_entity / 4 + long_breakout = calc_upper + prev_entity / 4 + short_breakout = calc_lower - prev_entity / 4 + else: + # 原有计算方式 + long_trigger = prev_entity_lower + prev_entity / 4 # 做多触发价 = 实体下边 + 实体/4(下四分之一处) + short_trigger = prev_entity_upper - prev_entity / 4 # 做空触发价 = 实体上边 - 实体/4(上四分之一处) + long_breakout = prev_entity_upper + prev_entity / 4 # 做多突破价 = 实体上边 + 实体/4 + short_breakout = prev_entity_lower - prev_entity / 4 # 做空突破价 = 实体下边 - 实体/4 + + # 上一根阴线 + 当前阳线:做多形态,不按上一根K线上三分之一做空 + prev_is_bearish = prev_kline['close'] < prev_kline['open'] + current_is_bullish = current_kline['close'] > current_kline['open'] + skip_short_by_upper_third = prev_is_bearish and current_is_bullish + # 上一根阳线 + 当前阴线:做空形态,不按上一根K线下三分之一做多 + prev_is_bullish = prev_kline['close'] > prev_kline['open'] + current_is_bearish = current_kline['close'] < current_kline['open'] + skip_long_by_lower_third = prev_is_bullish and current_is_bearish + + if use_current_open_as_base: + if prev_is_bullish_for_calc and current_open_above_prev_close: + logger.info(f"上一根阳线且当前开盘价({current_kline['open']:.2f})>上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") + else: + logger.info(f"上一根阴线且当前开盘价({current_kline['open']:.2f})<上一根收盘价({prev_kline['close']:.2f}),以当前开盘价为基准计算") + logger.info(f"当前价格: {current_price:.2f}, 上一根实体: {prev_entity:.4f}") + logger.info(f"上一根实体上边: {prev_entity_upper:.2f}, 下边: {prev_entity_lower:.2f}") + logger.info(f"做多触发价(下1/4): {long_trigger:.2f}, 做空触发价(上1/4): {short_trigger:.2f}") + logger.info(f"突破做多价(上1/4外): {long_breakout:.2f}, 突破做空价(下1/4外): {short_breakout:.2f}") + if skip_short_by_upper_third: + logger.info("上一根阴线+当前阳线(做多形态),不按上四分之一做空") + if skip_long_by_lower_third: + logger.info("上一根阳线+当前阴线(做空形态),不按下四分之一做多") + + # 无持仓时检查开仓信号 + if self.start == 0: + if current_price >= long_breakout and not skip_long_by_lower_third: + logger.info(f"触发做多信号!价格 {current_price:.2f} >= 突破价(上1/4外) {long_breakout:.2f}") + return ('long', long_breakout) + elif current_price <= short_breakout and not skip_short_by_upper_third: + logger.info(f"触发做空信号!价格 {current_price:.2f} <= 突破价(下1/4外) {short_breakout:.2f}") + return ('short', short_breakout) + + # 持仓时检查反手信号 + elif self.start == 1: # 持多仓 + # 反手条件1: 价格跌到上一根K线的上三分之一处(做空触发价);上一根阴线+当前阳线做多时跳过 + if current_price <= short_trigger and not skip_short_by_upper_third: + logger.info(f"持多反手做空!价格 {current_price:.2f} <= 触发价(上1/4) {short_trigger:.2f}") + return ('reverse_short', short_trigger) + + # 反手条件2: 上一根K线上阴线涨幅>0.01%,当前跌到上一根实体下边 + upper_shadow_pct = self.calculate_upper_shadow(prev_kline) + if upper_shadow_pct > 0.01 and current_price <= prev_entity_lower: + logger.info(f"持多反手做空!上阴线涨幅 {upper_shadow_pct:.4f}% > 0.01%," + f"价格 {current_price:.2f} <= 实体下边 {prev_entity_lower:.2f}") + return ('reverse_short', prev_entity_lower) + + elif self.start == -1: # 持空仓 + # 反手条件1: 价格涨到上一根K线的下三分之一处(做多触发价);上一根阳线+当前阴线做空时跳过 + if current_price >= long_trigger and not skip_long_by_lower_third: + logger.info(f"持空反手做多!价格 {current_price:.2f} >= 触发价(下1/4) {long_trigger:.2f}") + return ('reverse_long', long_trigger) + + # 反手条件2: 上一根K线下阴线跌幅>0.01%,当前涨到上一根实体上边 + lower_shadow_pct = self.calculate_lower_shadow(prev_kline) + if lower_shadow_pct > 0.01 and current_price >= prev_entity_upper: + logger.info(f"持空反手做多!下阴线跌幅 {lower_shadow_pct:.4f}% > 0.01%," + f"价格 {current_price:.2f} >= 实体上边 {prev_entity_upper:.2f}") + return ('reverse_long', prev_entity_upper) + + return None + + def can_open(self, current_kline_id): + """开仓前过滤:同一根 K 线只开一次 + 开仓冷却时间。仅用于 long/short 新开仓。""" + now = time.time() + if self.last_open_kline_id is not None and self.last_open_kline_id == current_kline_id: + logger.info(f"开仓频率控制:本 K 线({current_kline_id})已开过仓,跳过") + return False + if self.last_open_time is not None and now - self.last_open_time < self.open_cooldown_seconds: + remain = self.open_cooldown_seconds - (now - self.last_open_time) + logger.info(f"开仓冷却中,剩余 {remain:.0f} 秒") + return False + return True + + def can_reverse(self, current_price, trigger_price): + """反手前过滤:冷却时间 + 最小价差""" + now = time.time() + if self.last_reverse_time and now - self.last_reverse_time < self.reverse_cooldown_seconds: + remain = self.reverse_cooldown_seconds - (now - self.last_reverse_time) + logger.info(f"反手冷却中,剩余 {remain:.0f} 秒") + return False + + if trigger_price and trigger_price > 0: + move_pct = abs(current_price - trigger_price) / trigger_price * 100 + if move_pct < self.reverse_min_move_pct: + logger.info(f"反手价差不足: {move_pct:.4f}% < {self.reverse_min_move_pct}%") + return False + + return True + + def verify_no_position(self, max_retries=5, retry_interval=3): + """ + 验证当前无持仓 + 返回: True 表示无持仓可以开仓,False 表示有持仓不能开仓 + """ + for i in range(max_retries): + if self.get_position_status(): + if self.start == 0: + logger.info(f"确认无持仓,可以开仓") + return True + else: + logger.warning( + f"仍有持仓 (方向: {self.start}),等待 {retry_interval} 秒后重试 ({i + 1}/{max_retries})") + time.sleep(retry_interval) + else: + logger.warning(f"查询持仓状态失败,等待 {retry_interval} 秒后重试 ({i + 1}/{max_retries})") + time.sleep(retry_interval) + + logger.error(f"经过 {max_retries} 次重试仍有持仓或查询失败,放弃开仓") + return False + + def verify_position_direction(self, expected_direction): + """ + 验证当前持仓方向是否与预期一致 + expected_direction: 1 多仓, -1 空仓 + 返回: True 表示持仓方向正确,False 表示不正确 + """ + if self.get_position_status(): + if self.start == expected_direction: + logger.info(f"持仓方向验证成功: {self.start}") + return True + else: + logger.warning(f"持仓方向不符: 期望 {expected_direction}, 实际 {self.start}") + return False + else: + logger.error("查询持仓状态失败") + return False + + def execute_trade(self, signal, size=None): + """执行交易。size 不传或为 None 时使用 default_order_size。""" + signal_type, trigger_price = signal + size = self.default_order_size if size is None else size + + if signal_type == 'long': + # 开多前先确认无持仓 + logger.info(f"准备开多,触发价: {trigger_price:.2f}") + if not self.get_position_status(): + logger.error("开仓前查询持仓状态失败,放弃开仓") + return False + if self.start != 0: + logger.warning(f"开多前发现已有持仓 (方向: {self.start}),放弃开仓避免双向持仓") + return False + + logger.info(f"确认无持仓,执行开多") + self.开单(marketPriceLongOrder=1, size=size) + time.sleep(3) # 等待订单执行 + + # 验证开仓是否成功 + if self.verify_position_direction(1): + self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录 + self.last_open_time = time.time() + self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None) + logger.success("开多成功") + return True + else: + logger.error("开多后持仓验证失败") + return False + + elif signal_type == 'short': + # 开空前先确认无持仓 + logger.info(f"准备开空,触发价: {trigger_price:.2f}") + if not self.get_position_status(): + logger.error("开仓前查询持仓状态失败,放弃开仓") + return False + if self.start != 0: + logger.warning(f"开空前发现已有持仓 (方向: {self.start}),放弃开仓避免双向持仓") + return False + + logger.info(f"确认无持仓,执行开空") + self.开单(marketPriceLongOrder=-1, size=size) + time.sleep(3) # 等待订单执行 + + # 验证开仓是否成功 + if self.verify_position_direction(-1): + self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录 + self.last_open_time = time.time() + self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None) + logger.success("开空成功") + return True + else: + logger.error("开空后持仓验证失败") + return False + + elif signal_type == 'reverse_long': + # 平空 + 开多(反手做多):先平仓,确认无仓后再开多,避免双向持仓 + logger.info(f"执行反手做多,触发价: {trigger_price:.2f}") + self.平仓() + time.sleep(1) # 给交易所处理平仓的时间 + # 轮询确认已无持仓再开多(最多等约 10 秒) + for _ in range(10): + if self.get_position_status() and self.start == 0: + break + time.sleep(1) + if self.start != 0: + logger.warning("反手做多:平仓后仍有持仓,放弃本次开多") + return False + logger.info("已确认无持仓,执行开多") + self.开单(marketPriceLongOrder=1, size=size) + time.sleep(3) + + if self.verify_position_direction(1): + self.max_unrealized_pnl_seen = None + logger.success("反手做多成功") + self.last_reverse_time = time.time() + time.sleep(20) + return True + else: + logger.error("反手做多后持仓验证失败") + return False + + elif signal_type == 'reverse_short': + # 平多 + 开空(反手做空):先平仓,确认无仓后再开空 + logger.info(f"执行反手做空,触发价: {trigger_price:.2f}") + self.平仓() + time.sleep(1) + for _ in range(10): + if self.get_position_status() and self.start == 0: + break + time.sleep(1) + if self.start != 0: + logger.warning("反手做空:平仓后仍有持仓,放弃本次开空") + return False + logger.info("已确认无持仓,执行开空") + self.开单(marketPriceLongOrder=-1, size=size) + time.sleep(3) + + if self.verify_position_direction(-1): + self.max_unrealized_pnl_seen = None + logger.success("反手做空成功") + self.last_reverse_time = time.time() + time.sleep(20) + return True + else: + logger.error("反手做空后持仓验证失败") + return False + + return False + + def action(self): + """主循环""" + + logger.info("开始运行方案B(AI 策略)交易...") + + # 启动时设置全仓高杠杆 + if not self.set_leverage(): + logger.error("杠杆设置失败,程序继续运行但可能下单失败") + return + + page_start = True + + while True: + + if page_start: + # 打开浏览器 + for i in range(5): + if self.openBrowser(): + logger.info("浏览器打开成功") + break + else: + self.ding("打开浏览器失败!", error=True) + return + + # 进入交易页面 + self.page.get("https://derivatives.bitmart.com/zh-CN/futures/ETHUSDT") + self.click_safe('x://button[normalize-space(text()) ="市价"]') + + self.page.ele('x://*[@id="size_0"]').input(vals=25, clear=True) + + page_start = False + + try: + # 1. 获取当前价格 + current_price = self.get_current_price() + if not current_price: + logger.warning("获取价格失败,等待重试...") + time.sleep(2) + continue + + # 2. 每次循环都通过SDK获取真实持仓状态(避免状态不同步导致双向持仓) + if not self.get_position_status(): + logger.warning("获取持仓状态失败,等待重试...") + time.sleep(2) + continue + + logger.debug(f"当前持仓状态: {self.start} (0=无, 1=多, -1=空)") + + # 3. 止损/止盈/移动止损 + if self.start != 0: + pnl_usd = self.get_unrealized_pnl_usd() + if pnl_usd is not None: + # 固定止损:亏损达到 3 美元平仓 + if pnl_usd <= self.stop_loss_usd: + logger.info(f"仓位亏损 {pnl_usd:.2f} 美元 <= 止损 {self.stop_loss_usd} 美元,执行止损平仓") + self.平仓() + self.max_unrealized_pnl_seen = None + time.sleep(3) + continue + # 更新持仓期间最大盈利(用于移动止损) + if self.max_unrealized_pnl_seen is None: + self.max_unrealized_pnl_seen = pnl_usd + else: + self.max_unrealized_pnl_seen = max(self.max_unrealized_pnl_seen, pnl_usd) + # 移动止损:盈利曾达到 activation 后,从最高盈利回撤 trailing_distance 则平仓 + if self.max_unrealized_pnl_seen >= self.trailing_activation_usd: + if pnl_usd < self.max_unrealized_pnl_seen - self.trailing_distance_usd: + logger.info(f"移动止损:当前盈利 {pnl_usd:.2f} 从最高 {self.max_unrealized_pnl_seen:.2f} 回撤 >= {self.trailing_distance_usd} 美元,平仓") + self.平仓() + self.max_unrealized_pnl_seen = None + time.sleep(3) + continue + # 止盈:盈利达到 take_profit_usd 平仓 + if pnl_usd >= self.take_profit_usd: + logger.info(f"仓位盈利 {pnl_usd:.2f} 美元 >= {self.take_profit_usd} 美元,执行止盈平仓") + self.平仓() + self.max_unrealized_pnl_seen = None + time.sleep(3) + continue + + # 4. 方案B:仅在新的 15 分钟 K 线时取一次信号(0=观望, 1=做多, 2=做空) + current_15m_id = int(time.time() // 900) * 900 # 15 分钟 bar 起始时间戳 + signal = None + if current_15m_id != self.last_kline_time: + self.last_kline_time = current_15m_id + logger.info(f"进入新 15m K 线: {current_15m_id}") + raw = get_live_signal(period=15) + if raw == 1: + if self.start == 0: + signal = ('long', current_price) + elif self.start == -1: + signal = ('reverse_long', current_price) + elif raw == 2: + if self.start == 0: + signal = ('short', current_price) + elif self.start == 1: + signal = ('reverse_short', current_price) + + # 5. 反手过滤:冷却时间 + 最小价差 + if signal and signal[0].startswith('reverse_'): + if not self.can_reverse(current_price, signal[1]): + signal = None + + # 5.5 开仓频率过滤:同一根 15m K 线只开一次 + 开仓冷却 + if signal and signal[0] in ('long', 'short'): + if not self.can_open(current_15m_id): + signal = None + else: + self._current_kline_id_for_open = current_15m_id # 供 execute_trade 成功后记录 + + # 6. 有信号则执行交易 + if signal: + trade_success = self.execute_trade(signal) + if trade_success: + logger.success(f"交易执行完成: {signal[0]}, 当前持仓状态: {self.start}") + page_start = True + else: + logger.warning(f"交易执行失败或被阻止: {signal[0]}") + + # 短暂等待后继续循环(同一根K线遇到信号就操作) + time.sleep(0.1) + + if page_start: + self.page.close() + time.sleep(5) + + except KeyboardInterrupt: + logger.info("用户中断,程序退出") + break + except Exception as e: + logger.error(f"主循环异常: {e}") + time.sleep(5) + + +if __name__ == '__main__': + BitmartFuturesTransaction(bit_id="f2320f57e24c45529a009e1541e25961").action()