add files

This commit is contained in:
songkunling
2025-07-25 17:35:01 +08:00
commit 559d78388d
19 changed files with 1106 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.bollinger_period = 20
self.bollinger_std_dev = 2
def _calculate_indicators(self, df):
"""
计算布林带指标
"""
mean = df['close'].rolling(self.bollinger_period).mean()
std = df['close'].rolling(self.bollinger_period).std()
df['upper_band'] = mean + self.bollinger_std_dev * std
df['lower_band'] = mean - self.bollinger_std_dev * std
return df
def generate_signal(self):
"""
布林带策略实盘:
当价格跌破下轨买入,涨破上轨卖出。
"""
rates = get_rates(self.symbol, self.timeframe, self.bollinger_period + 30)
if rates is None or len(rates) < self.bollinger_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['close'].iloc[-2] < df['lower_band'].iloc[-2]:
logger.info(f"价格跌破下轨,产生买入信号: {self.symbol}")
return 1
elif df['close'].iloc[-2] > df['upper_band'].iloc[-2]:
logger.info(f"价格涨破上轨,产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
布林带策略回测:
价格突破下轨买入,突破上轨卖出
返回信号序列:1买入,-1卖出,0无操作
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(self.bollinger_period, len(df)):
if df['close'].iloc[i-1] < df['lower_band'].iloc[i-1]:
signals.iat[i] = 1
elif df['close'].iloc[i-1] > df['upper_band'].iloc[i-1]:
signals.iat[i] = -1
return signals
+68
View File
@@ -0,0 +1,68 @@
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
from utils import get_rates, has_open_position, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
def _calculate_indicators(self, df):
"""
计算日内突破指标
"""
df['time'] = pd.to_datetime(df['time'], unit='s')
today = datetime.now().date()
day_data = df[df['time'].dt.date == today]
if day_data.empty:
return df, None, None
day_high = day_data['high'].max()
day_low = day_data['low'].min()
return df, day_high, day_low
def generate_signal(self):
"""
日内突破策略实盘
当价格突破当日最高买入,突破当日最低卖出
"""
rates = get_rates(self.symbol, self.timeframe, 1440) # 24 hours * 60 minutes
if rates is None or len(rates) < 2:
return 0
df = pd.DataFrame(rates)
df, day_high, day_low = self._calculate_indicators(df)
if day_high is None or day_low is None:
return 0
if df['close'].iloc[-2] > day_high:
logger.info(f"价格突破当日最高,产生买入信号: {self.symbol}")
return 1
elif df['close'].iloc[-2] < day_low:
logger.info(f"价格突破当日最低,产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
日内突破回测方法
计算每个交易日的高低点,突破买卖信号
"""
df = df.copy()
df['time'] = pd.to_datetime(df['time'], unit='s')
signals = pd.Series(0, index=df.index)
grouped = df.groupby(df['time'].dt.date)
for date, group in grouped:
day_high = group['high'].max()
day_low = group['low'].min()
for i, row in group.iterrows():
if row['close'] > day_high:
signals.loc[i] = 1
elif row['close'] < day_low:
signals.loc[i] = -1
return signals
+60
View File
@@ -0,0 +1,60 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, has_open_position, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.kdj_period = 9
self.kdj_buy_threshold = 10
self.kdj_sell_threshold = 90
def _calculate_indicators(self, df):
"""
计算KDJ指标
"""
low_min = df['low'].rolling(self.kdj_period).min()
high_max = df['high'].rolling(self.kdj_period).max()
rsv = (df['close'] - low_min) / (high_max - low_min) * 100
df['k'] = rsv.ewm(com=2).mean()
df['d'] = df['k'].ewm(com=2).mean()
df['j'] = 3 * df['k'] - 2 * df['d']
return df
def generate_signal(self):
"""
KDJ策略实盘
J值小于10买入,大于90卖出
"""
rates = get_rates(self.symbol, self.timeframe, self.kdj_period + 30)
if rates is None or len(rates) < self.kdj_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['j'].iloc[-2] < self.kdj_buy_threshold:
logger.info(f"J值小于{self.kdj_buy_threshold},产生买入信号: {self.symbol}")
return 1
elif df['j'].iloc[-2] > self.kdj_sell_threshold:
logger.info(f"J值大于{self.kdj_sell_threshold},产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
KDJ回测方法
根据J值极端生成信号
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(self.kdj_period, len(df)):
if df['j'].iloc[i-1] < self.kdj_buy_threshold:
signals.iat[i] = 1
elif df['j'].iloc[i-1] > self.kdj_sell_threshold:
signals.iat[i] = -1
return signals
+56
View File
@@ -0,0 +1,56 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.fast_ma_period = 5
self.slow_ma_period = 20
def _calculate_indicators(self, df):
"""
计算技术指标
"""
df['fast_ma'] = df['close'].rolling(self.fast_ma_period).mean()
df['slow_ma'] = df['close'].rolling(self.slow_ma_period).mean()
return df
def generate_signal(self):
"""
均线交叉策略实盘:
短期均线上穿长期均线买入,下穿卖出。
"""
rates = get_rates(self.symbol, self.timeframe, self.slow_ma_period + 30)
if rates is None or len(rates) < self.slow_ma_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['fast_ma'].iloc[-2] > df['slow_ma'].iloc[-2] and df['fast_ma'].iloc[-3] <= df['slow_ma'].iloc[-3]:
logger.info(f"短期均线上穿长期均线,产生买入信号: {self.symbol}")
return 1
elif df['fast_ma'].iloc[-2] < df['slow_ma'].iloc[-2] and df['fast_ma'].iloc[-3] >= df['slow_ma'].iloc[-3]:
logger.info(f"短期均线下穿长期均线,产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
均线交叉回测:
短期均线和长期均线交叉产生信号
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
# 从 slow_ma_period 开始循环,避免早期数据 NaN 问题
for i in range(self.slow_ma_period, len(df)):
if df['fast_ma'].iloc[i-1] > df['slow_ma'].iloc[i-1] and df['fast_ma'].iloc[i-2] <= df['slow_ma'].iloc[i-2]:
signals.iat[i] = 1
elif df['fast_ma'].iloc[i-1] < df['slow_ma'].iloc[i-1] and df['fast_ma'].iloc[i-2] >= df['slow_ma'].iloc[i-2]:
signals.iat[i] = -1
return signals
+58
View File
@@ -0,0 +1,58 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, has_open_position, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.fast_ema_period = 12
self.slow_ema_period = 26
self.signal_period = 9
def _calculate_indicators(self, df):
"""
计算MACD指标
"""
df['exp12'] = df['close'].ewm(span=self.fast_ema_period, adjust=False).mean()
df['exp26'] = df['close'].ewm(span=self.slow_ema_period, adjust=False).mean()
df['dif'] = df['exp12'] - df['exp26']
df['dea'] = df['dif'].ewm(span=self.signal_period, adjust=False).mean()
return df
def generate_signal(self):
"""
MACD策略实盘
DIF线上穿DEA买入,反之卖出
"""
rates = get_rates(self.symbol, self.timeframe, self.slow_ema_period + self.signal_period + 30)
if rates is None or len(rates) < self.slow_ema_period + self.signal_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['dif'].iloc[-2] > df['dea'].iloc[-2] and df['dif'].iloc[-3] <= df['dea'].iloc[-3]:
logger.info(f"DIF线上穿DEA,产生买入信号: {self.symbol}")
return 1
elif df['dif'].iloc[-2] < df['dea'].iloc[-2] and df['dif'].iloc[-3] >= df['dea'].iloc[-3]:
logger.info(f"DIF线下穿DEA,产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
MACD回测方法
根据DIF和DEA金叉死叉生成信号
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(2, len(df)):
if df['dif'].iloc[i-1] > df['dea'].iloc[i-1] and df['dif'].iloc[i-2] <= df['dea'].iloc[i-2]:
signals.iat[i] = 1
elif df['dif'].iloc[i-1] < df['dea'].iloc[i-1] and df['dif'].iloc[i-2] >= df['dea'].iloc[i-2]:
signals.iat[i] = -1
return signals
+57
View File
@@ -0,0 +1,57 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.mean_reversion_period = 20
self.mean_reversion_std_dev = 2
def _calculate_indicators(self, df):
"""
计算均值回归指标
"""
mean = df['close'].rolling(self.mean_reversion_period).mean()
std = df['close'].rolling(self.mean_reversion_period).std()
df['upper_band'] = mean + self.mean_reversion_std_dev * std
df['lower_band'] = mean - self.mean_reversion_std_dev * std
return df
def generate_signal(self):
"""
均值回归策略实盘:
当价格超过20日均线正负2个标准差买卖。
"""
rates = get_rates(self.symbol, self.timeframe, self.mean_reversion_period + 30)
if rates is None or len(rates) < self.mean_reversion_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['close'].iloc[-2] > df['upper_band'].iloc[-2]:
logger.info(f"价格超过上轨,产生卖出信号: {self.symbol}")
return -1
elif df['close'].iloc[-2] < df['lower_band'].iloc[-2]:
logger.info(f"价格低于下轨,产生买入信号: {self.symbol}")
return 1
return 0
def run_backtest(self, df):
"""
均值回归回测:
价格突破上下轨卖出/买入
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(self.mean_reversion_period, len(df)):
if df['close'].iloc[i-1] > df['upper_band'].iloc[i-1]:
signals.iat[i] = -1
elif df['close'].iloc[i-1] < df['lower_band'].iloc[i-1]:
signals.iat[i] = 1
return signals
+54
View File
@@ -0,0 +1,54 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, has_open_position, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.breakout_period = 20
def _calculate_indicators(self, df):
"""
计算动量突破指标
"""
df['high_20'] = df['high'].rolling(self.breakout_period).max()
df['low_20'] = df['low'].rolling(self.breakout_period).min()
return df
def generate_signal(self):
"""
动量突破策略实盘
价格突破过去20根K线最高点买入,突破最低点卖出
"""
rates = get_rates(self.symbol, self.timeframe, self.breakout_period + 30)
if rates is None or len(rates) < self.breakout_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['close'].iloc[-2] > df['high_20'].iloc[-3]:
logger.info(f"价格突破{self.breakout_period}日最高点,产生买入信号: {self.symbol}")
return 1
elif df['close'].iloc[-2] < df['low_20'].iloc[-3]:
logger.info(f"价格突破{self.breakout_period}日最低点,产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
动量突破回测方法
过去20根K线最高最低突破生成买卖信号
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(self.breakout_period, len(df)):
if df['close'].iloc[i-1] > df['high_20'].iloc[i-2]:
signals.iat[i] = 1
elif df['close'].iloc[i-1] < df['low_20'].iloc[i-2]:
signals.iat[i] = -1
return signals
+79
View File
@@ -0,0 +1,79 @@
import pandas as pd
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
# --- 策略核心参数 ---
# 固定止损线:亏损10%则卖出
self.stop_loss_pct = -0.10
# 利润回撤百分比:从最高利润点回撤30%则卖出
self.profit_retracement_pct = 0.30
# 追踪止损的激活阈值:当利润超过5%后,才开始启动追踪止损逻辑
self.min_profit_for_trailing = 0.05
def generate_signal(self):
"""
此策略为资金管理和退出策略,不产生独立的买入信号。
实盘逻辑应与其他策略结合,此处仅为框架完整性。
"""
logger.warning("ProfitProtect策略是一个退出策略,不应单独用于实盘产生信号。")
return 0
def run_backtest(self, df):
"""
盈利保护策略回测:
- 固定止损:亏损10%卖出。
- 追踪止损:利润超过5%后启动,从最高利润点回撤30%卖出。
为了独立回测,本策略会在一开始买入,然后应用退出逻辑。
"""
df = df.copy()
signals = pd.Series(0, index=df.index)
if len(df) < 2:
return signals
# --- 回测状态变量 ---
position_open = False
entry_price = 0.0
peak_profit_pct = 0.0 # 记录达到的最高利润百分比
for i in range(len(df)):
# 如果没有持仓,就在第一个机会买入(用于独立回测)
if not position_open:
position_open = True
entry_price = df['close'].iloc[i]
signals.iat[i] = 1 # 买入信号
peak_profit_pct = 0.0 # 重置最高利润
continue
# 如果有持仓,则执行退出逻辑
if position_open:
current_price = df['close'].iloc[i]
current_profit_pct = (current_price - entry_price) / entry_price
# 1. 更新最高利润点
peak_profit_pct = max(peak_profit_pct, current_profit_pct)
# 2. 检查固定止损条件
if current_profit_pct <= self.stop_loss_pct:
logger.info(f"索引 {i}: 触发固定止损。入场价: {entry_price:.2f}, 当前价: {current_price:.2f}, 亏损: {current_profit_pct:.2%}")
signals.iat[i] = -1 # 卖出信号
position_open = False # 平仓
continue
# 3. 检查追踪止损条件
# 只有当最高利润超过了激活阈值,才开始计算回撤
if peak_profit_pct > self.min_profit_for_trailing:
retracement_from_peak = (peak_profit_pct - current_profit_pct)
# 避免除以零或负数的情况
if peak_profit_pct > 0:
retracement_pct = retracement_from_peak / peak_profit_pct
if retracement_pct >= self.profit_retracement_pct:
logger.info(f"索引 {i}: 触发追踪止损。最高利润: {peak_profit_pct:.2%}, 当前利润: {current_profit_pct:.2%}, 回撤超过30%")
signals.iat[i] = -1 # 卖出信号
position_open = False # 平仓
continue
return signals
+113
View File
@@ -0,0 +1,113 @@
import pandas as pd
from logger import logger
from utils import get_rates
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
# --- 策略核心参数 ---
self.trend_period = 50
self.retracement_tolerance = 0.30
# --- 策略状态变量 ---
self.current_trend = "none" # none, uptrend, downtrend
self.trend_peak = 0.0 # 上升趋势中的最高价
self.trend_trough = float('inf') # 下降趋势中的最低价
def generate_signal(self):
"""
带状态维护的实盘信号生成方法。
"""
# 获取足够的数据来计算滚动高低点
rates = get_rates(self.symbol, 1, self.trend_period + 5)
if rates is None or len(rates) < self.trend_period:
return 0 # 数据不足,不产生信号
df = pd.DataFrame(rates)
# 获取当前价格和用于判断突破的历史高低点
current_price = df['close'].iloc[-1]
high_period = df['high'].rolling(self.trend_period).max().iloc[-2]
low_period = df['low'].rolling(self.trend_period).min().iloc[-2]
signal = 0
# 状态 1: 当前无趋势,等待趋势开始
if self.current_trend == "none":
if current_price > high_period:
self.current_trend = "uptrend"
self.trend_peak = current_price
signal = 1
logger.info(f"实盘: 突破进入上升趋势,买入价: {current_price:.2f}")
elif current_price < low_period:
self.current_trend = "downtrend"
self.trend_trough = current_price
signal = -1
logger.info(f"实盘: 跌破进入下降趋势,卖出价: {current_price:.2f}")
# 状态 2: 当前处于上升趋势
elif self.current_trend == "uptrend":
if current_price < self.trend_peak * (1 - self.retracement_tolerance):
logger.info(f"实盘: 上升趋势结束。最高点: {self.trend_peak:.2f}, 当前价: {current_price:.2f}。平仓卖出。")
signal = -1
self.current_trend = "none" # 重置状态
else:
self.trend_peak = max(self.trend_peak, current_price)
# 状态 3: 当前处于下降趋势
elif self.current_trend == "downtrend":
if current_price > self.trend_trough * (1 + self.retracement_tolerance):
logger.info(f"实盘: 下降趋势结束。最低点: {self.trend_trough:.2f}, 当前价: {current_price:.2f}。平仓买入。")
signal = 1
self.current_trend = "none" # 重置状态
else:
self.trend_trough = min(self.trend_trough, current_price)
return signal
def run_backtest(self, df):
"""
带容错的趋势跟踪策略回测:
- 突破N周期高点,进入上升趋势,回撤30%则趋势结束。
- 跌破N周期低点,进入下降趋势,反弹30%则趋势结束。
"""
df = df.copy()
signals = pd.Series(0, index=df.index)
df['high_period'] = df['high'].rolling(self.trend_period).max().shift(1)
df['low_period'] = df['low'].rolling(self.trend_period).min().shift(1)
# 回测时使用局部变量来管理状态,避免干扰实盘状态
backtest_trend = "none"
backtest_peak = 0.0
backtest_trough = float('inf')
for i in range(self.trend_period, len(df)):
current_price = df['close'].iloc[i]
if backtest_trend == "none":
if current_price > df['high_period'].iloc[i]:
backtest_trend = "uptrend"
backtest_peak = current_price
signals.iat[i] = 1
elif current_price < df['low_period'].iloc[i]:
backtest_trend = "downtrend"
backtest_trough = current_price
signals.iat[i] = -1
elif backtest_trend == "uptrend":
if current_price < backtest_peak * (1 - self.retracement_tolerance):
signals.iat[i] = -1
backtest_trend = "none"
else:
backtest_peak = max(backtest_peak, current_price)
elif backtest_trend == "downtrend":
if current_price > backtest_trough * (1 + self.retracement_tolerance):
signals.iat[i] = 1
backtest_trend = "none"
else:
backtest_trough = min(backtest_trough, current_price)
return signals
+59
View File
@@ -0,0 +1,59 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.rsi_period = 14
self.rsi_buy_threshold = 30
self.rsi_sell_threshold = 70
def _calculate_indicators(self, df):
"""
计算RSI指标
"""
delta = df['close'].diff()
gain = delta.where(delta > 0, 0).rolling(self.rsi_period).mean()
loss = -delta.where(delta < 0, 0).rolling(self.rsi_period).mean()
rs = gain / loss
df['rsi'] = 100 - (100 / (1 + rs))
return df
def generate_signal(self):
"""
RSI策略实盘:
RSI < 30买入,RSI > 70卖出。
"""
rates = get_rates(self.symbol, self.timeframe, self.rsi_period + 30)
if rates is None or len(rates) < self.rsi_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['rsi'].iloc[-2] < self.rsi_buy_threshold:
logger.info(f"RSI小于{self.rsi_buy_threshold},产生买入信号: {self.symbol}")
return 1
elif df['rsi'].iloc[-2] > self.rsi_sell_threshold:
logger.info(f"RSI大于{self.rsi_sell_threshold},产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
RSI回测:
RSI < 30买入,RSI > 70卖出。
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(self.rsi_period, len(df)):
if df['rsi'].iloc[i-1] < self.rsi_buy_threshold:
signals.iat[i] = 1
elif df['rsi'].iloc[i-1] > self.rsi_sell_threshold:
signals.iat[i] = -1
return signals
+54
View File
@@ -0,0 +1,54 @@
import MetaTrader5 as mt5
import pandas as pd
from utils import get_rates, has_open_position, close_all, send_order
from logger import logger
class Strategy:
def __init__(self):
self.symbol = "XAUUSD"
self.timeframe = mt5.TIMEFRAME_M1
self.turtle_period = 20
def _calculate_indicators(self, df):
"""
计算海龟交易指标
"""
df['high_20'] = df['high'].rolling(self.turtle_period).max()
df['low_20'] = df['low'].rolling(self.turtle_period).min()
return df
def generate_signal(self):
"""
海龟交易策略实盘
20日最高突破买入,20日最低突破卖出
"""
rates = get_rates(self.symbol, self.timeframe, self.turtle_period + 30)
if rates is None or len(rates) < self.turtle_period:
return 0
df = pd.DataFrame(rates)
df = self._calculate_indicators(df)
if df['close'].iloc[-2] > df['high_20'].iloc[-3]:
logger.info(f"价格突破{self.turtle_period}日最高点,产生买入信号: {self.symbol}")
return 1
elif df['close'].iloc[-2] < df['low_20'].iloc[-3]:
logger.info(f"价格突破{self.turtle_period}日最低点,产生卖出信号: {self.symbol}")
return -1
return 0
def run_backtest(self, df):
"""
海龟交易回测方法
根据20日高低突破生成买卖信号
"""
df = df.copy()
df = self._calculate_indicators(df)
signals = pd.Series(0, index=df.index)
for i in range(self.turtle_period, len(df)):
if df['close'].iloc[i-1] > df['high_20'].iloc[i-2]:
signals.iat[i] = 1
elif df['close'].iloc[i-1] < df['low_20'].iloc[i-2]:
signals.iat[i] = -1
return signals