mirror of
https://github.com/silencesdg/mt5_python_ea_suite.git
synced 2026-08-09 00:47:54 +00:00
add files
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user