diff --git a/20260516-波段交易策略/README.md b/20260516-波段交易策略/README.md new file mode 100644 index 0000000..0811845 --- /dev/null +++ b/20260516-波段交易策略/README.md @@ -0,0 +1 @@ +# 波段交易策略 \ No newline at end of file diff --git a/20260516-突破策略/20260516.mq5 b/20260516-突破策略/20260516.mq5 deleted file mode 100644 index 2351f89..0000000 --- a/20260516-突破策略/20260516.mq5 +++ /dev/null @@ -1,306 +0,0 @@ -//+------------------------------------------------------------------+ -//| BreakoutMarker.mq5 | -//| 突破极值点标记EA | -//| 用于标记突破策略中的极值点位置 | -//+------------------------------------------------------------------+ -#property copyright "Breakout Strategy" -#property version "1.00" -#property indicator_chart_window -#property indicator_buffers 2 -#property indicator_plots 2 - -//--- 绘图设置 -#property indicator_label1 "高点极值" -#property indicator_type1 DRAW_ARROW -#property indicator_color1 clrRed -#property indicator_width1 3 - -#property indicator_label2 "低点极值" -#property indicator_type2 DRAW_ARROW -#property indicator_color2 clrLime -#property indicator_width2 3 - -//+------------------------------------------------------------------+ -//| 输入参数 | -//+------------------------------------------------------------------+ -input int InpMAPeriod = 14; // MA周期 -input int InpWaveThreshold = 1000; // 波段阈值(点数) -input bool InpShowDebugInfo = true; // 显示调试信息 - -//+------------------------------------------------------------------+ -//| 全局变量 | -//+------------------------------------------------------------------+ -int ma_handle; // MA指标句柄 -double HighExtremeBuffer[]; // 高点极值缓冲区 -double LowExtremeBuffer[]; // 低点极值缓冲区 - -//+------------------------------------------------------------------+ -//| 自定义指标初始化函数 | -//+------------------------------------------------------------------+ -int OnInit() -{ - // 创建MA指标 - ma_handle = iMA(_Symbol, PERIOD_CURRENT, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); - if(ma_handle == INVALID_HANDLE) { - Print("创建MA指标失败"); - return(INIT_FAILED); - } - - // 设置指标缓冲区 - SetIndexBuffer(0, HighExtremeBuffer, INDICATOR_DATA); - SetIndexBuffer(1, LowExtremeBuffer, INDICATOR_DATA); - - // 设置箭头代码 - PlotIndexSetInteger(0, PLOT_ARROW, 234); // 下箭头(标记高点) - PlotIndexSetInteger(1, PLOT_ARROW, 233); // 上箭头(标记低点) - - PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, -10); - PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, 10); - - // 设置数组为时间序列 - ArraySetAsSeries(HighExtremeBuffer, true); - ArraySetAsSeries(LowExtremeBuffer, true); - - // 设置指标名称 - IndicatorSetString(INDICATOR_SHORTNAME, "突破极值点标记"); - - Print("突破极值点标记EA初始化成功"); - Print("参数 - MA周期:", InpMAPeriod, ", 波段阈值:", InpWaveThreshold, "点"); - - return(INIT_SUCCEEDED); -} - -//+------------------------------------------------------------------+ -//| 自定义指标反初始化函数 | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) -{ - if(ma_handle != INVALID_HANDLE) - IndicatorRelease(ma_handle); - - Print("突破极值点标记EA已卸载"); -} - -//+------------------------------------------------------------------+ -//| 自定义指标迭代函数 | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, - const int prev_calculated, - const datetime &time[], - const double &open[], - const double &high[], - const double &low[], - const double &close[], - const long &tick_volume[], - const long &volume[], - const int &spread[]) -{ - if(InpShowDebugInfo && prev_calculated == 0) - Print("OnCalculate 首次调用 - rates_total:", rates_total); - - if(rates_total < InpMAPeriod + 2) { - if(InpShowDebugInfo) - Print("K线数量不足: ", rates_total); - return(0); - } - - // 设置数组为时间序列 - ArraySetAsSeries(time, true); - ArraySetAsSeries(open, true); - ArraySetAsSeries(high, true); - ArraySetAsSeries(low, true); - ArraySetAsSeries(close, true); - - // 获取MA数据 - double ma_array[]; - ArraySetAsSeries(ma_array, true); - int copied = CopyBuffer(ma_handle, 0, 0, rates_total, ma_array); - if(copied <= 0) { - if(InpShowDebugInfo) - Print("复制MA数据失败,返回值:", copied); - return(0); - } - - if(InpShowDebugInfo && prev_calculated == 0) - Print("MA数据复制成功,数量:", copied); - - // 初始化缓冲区 - ArrayInitialize(HighExtremeBuffer, 0); - ArrayInitialize(LowExtremeBuffer, 0); - - // 识别所有突破K线 - int breakout_bars[]; - int breakout_types[]; - ArrayResize(breakout_bars, 0); - ArrayResize(breakout_types, 0); - - for(int i = rates_total - InpMAPeriod - 1; i >= 1; i--) { - int breakout_type = CheckBreakout(i, open, close, ma_array); - if(breakout_type != 0) { - int size = ArraySize(breakout_bars); - ArrayResize(breakout_bars, size + 1); - ArrayResize(breakout_types, size + 1); - breakout_bars[size] = i; - breakout_types[size] = breakout_type; - } - } - - if(InpShowDebugInfo) - Print("共检测到 ", ArraySize(breakout_bars), " 个突破K线"); - - // 处理突破K线并计算极值点 - ProcessBreakouts(breakout_bars, breakout_types, high, low, time); - - return(rates_total); -} - -//+------------------------------------------------------------------+ -//| 检查是否是突破K线 | -//+------------------------------------------------------------------+ -int CheckBreakout(int index, const double &open[], const double &close[], const double &ma[]) -{ - // 多单突破: 开盘 < MA, 收盘 > MA - if(open[index] < ma[index] && close[index] > ma[index]) - return 1; - - // 空单突破: 开盘 > MA, 收盘 < MA - if(open[index] > ma[index] && close[index] < ma[index]) - return -1; - - return 0; -} - -//+------------------------------------------------------------------+ -//| 处理所有突破K线并计算极值点 | -//+------------------------------------------------------------------+ -void ProcessBreakouts(int &breakout_bars[], int &breakout_types[], - const double &high[], const double &low[], - const datetime &time[]) -{ - int total = ArraySize(breakout_bars); - if(total < 2) return; - - // 过滤连续同向突破 - int filtered_bars[]; - int filtered_types[]; - ArrayResize(filtered_bars, 0); - ArrayResize(filtered_types, 0); - - for(int i = 0; i < total; i++) { - int current_bar = breakout_bars[i]; - int current_type = breakout_types[i]; - - // 检查是否有后续同向突破 - bool skip = false; - for(int j = i + 1; j < total; j++) { - if(breakout_types[j] != current_type) - break; // 遇到反向突破,停止检查 - - // 比较哪个更极端 - if(current_type == 1) { // 多单突破,保留最低价更低的 - if(low[breakout_bars[j]] < low[current_bar]) { - skip = true; - break; - } - } else { // 空单突破,保留最高价更高的 - if(high[breakout_bars[j]] > high[current_bar]) { - skip = true; - break; - } - } - } - - if(!skip) { - int size = ArraySize(filtered_bars); - ArrayResize(filtered_bars, size + 1); - ArrayResize(filtered_types, size + 1); - filtered_bars[size] = current_bar; - filtered_types[size] = current_type; - } - } - - if(InpShowDebugInfo) - Print("过滤后剩余 ", ArraySize(filtered_bars), " 个有效突破K线"); - - // 计算极值点并应用波段阈值过滤 - double last_extreme_price = 0; - int last_extreme_bar = -1; - int last_extreme_type = 0; - - for(int i = 0; i < ArraySize(filtered_bars) - 1; i++) { - int current_bar = filtered_bars[i]; - int current_type = filtered_types[i]; - int next_bar = filtered_bars[i + 1]; - - // 计算当前段的极值 - double extreme_price = 0; - int extreme_bar = current_bar; - - if(current_type == 1) { // 多单突破后找最高价 - extreme_price = high[current_bar]; - for(int j = current_bar; j >= next_bar; j--) { - if(high[j] > extreme_price) { - extreme_price = high[j]; - extreme_bar = j; - } - } - } else { // 空单突破后找最低价 - extreme_price = low[current_bar]; - for(int j = current_bar; j >= next_bar; j--) { - if(low[j] < extreme_price) { - extreme_price = low[j]; - extreme_bar = j; - } - } - } - - // 应用波段阈值过滤 - if(last_extreme_price != 0) { - double price_diff = MathAbs(extreme_price - last_extreme_price); - double price_diff_points = price_diff / _Point; - - if(InpShowDebugInfo) { - Print("索引 ", i, " - 极值:", extreme_price, - ", 价差:", (int)price_diff_points, "点", - ", 时间:", TimeToString(time[extreme_bar])); - } - - if(price_diff_points >= InpWaveThreshold) { - // 标记上一个极值点 - MarkExtreme(last_extreme_bar, last_extreme_price, last_extreme_type, high, low); - - // 更新为当前极值点 - last_extreme_price = extreme_price; - last_extreme_bar = extreme_bar; - last_extreme_type = current_type; - } - // 如果不满足阈值,不更新last_extreme,继续用原极值点比较 - } else { - // 第一个极值点,直接记录 - last_extreme_price = extreme_price; - last_extreme_bar = extreme_bar; - last_extreme_type = current_type; - } - } - - // 标记最后一个极值点 - if(last_extreme_bar >= 0) { - MarkExtreme(last_extreme_bar, last_extreme_price, last_extreme_type, high, low); - } -} - -//+------------------------------------------------------------------+ -//| 标记极值点 | -//+------------------------------------------------------------------+ -void MarkExtreme(int bar, double price, int type, const double &high[], const double &low[]) -{ - if(type == 1) { // 多单突破形成的高点 - HighExtremeBuffer[bar] = price; - if(InpShowDebugInfo) - Print("标记高点极值 - 索引:", bar, ", 价格:", price); - } else { // 空单突破形成的低点 - LowExtremeBuffer[bar] = price; - if(InpShowDebugInfo) - Print("标记低点极值 - 索引:", bar, ", 价格:", price); - } -} diff --git a/20260516-突破策略/20260516_Trade.mq5 b/20260516-突破策略/20260516_Breakout.mq5 similarity index 100% rename from 20260516-突破策略/20260516_Trade.mq5 rename to 20260516-突破策略/20260516_Breakout.mq5 diff --git a/20260516-突破策略/20260516_EA.mq5 b/20260516-突破策略/20260516_EA.mq5 deleted file mode 100644 index 3add4c6..0000000 --- a/20260516-突破策略/20260516_EA.mq5 +++ /dev/null @@ -1,346 +0,0 @@ -//+------------------------------------------------------------------+ -//| 20260516_EA.mq5 | -//| 突破极值点标记EA (Expert Advisor版本) | -//+------------------------------------------------------------------+ -#property copyright "Breakout Strategy" -#property version "1.00" -#property strict - -//+------------------------------------------------------------------+ -//| 输入参数 | -//+------------------------------------------------------------------+ -input int InpMAPeriod = 14; // MA周期 -input int InpWaveThreshold = 1000; // 波段阈值(点数) -input bool InpShowDebugInfo = true; // 显示调试信息 -input color InpHighExtremeColor = clrRed; // 高点极值颜色 -input color InpLowExtremeColor = clrLime; // 低点极值颜色 - -//+------------------------------------------------------------------+ -//| 全局变量 | -//+------------------------------------------------------------------+ -int ma_handle; // MA指标句柄 -datetime last_process_time = 0; // 上次处理时间 - -//+------------------------------------------------------------------+ -//| Expert initialization function | -//+------------------------------------------------------------------+ -int OnInit() -{ - // 创建MA指标 - ma_handle = iMA(_Symbol, PERIOD_CURRENT, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE); - if(ma_handle == INVALID_HANDLE) { - Print("创建MA指标失败"); - return(INIT_FAILED); - } - - Print("========================================"); - Print("突破极值点标记EA初始化成功"); - Print("品种:", _Symbol); - Print("周期:", EnumToString(Period())); - Print("MA周期:", InpMAPeriod); - Print("波段阈值:", InpWaveThreshold, "点 (", InpWaveThreshold/100.0, "美元)"); - Print("========================================"); - - // 删除旧的标记对象 - ObjectsDeleteAll(0, "Extreme_"); - - // 处理历史数据 - ProcessHistory(); - - return(INIT_SUCCEEDED); -} - -//+------------------------------------------------------------------+ -//| Expert deinitialization function | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) -{ - if(ma_handle != INVALID_HANDLE) - IndicatorRelease(ma_handle); - - Print("突破极值点标记EA已卸载"); -} - -//+------------------------------------------------------------------+ -//| Expert tick function | -//+------------------------------------------------------------------+ -void OnTick() -{ - // 每根新K线处理一次 - datetime current_time = iTime(_Symbol, PERIOD_CURRENT, 0); - if(current_time == last_process_time) - return; - - last_process_time = current_time; - - // 重新处理历史数据 - ProcessHistory(); -} - -//+------------------------------------------------------------------+ -//| 处理历史数据 | -//+------------------------------------------------------------------+ -void ProcessHistory() -{ - int bars = Bars(_Symbol, PERIOD_CURRENT); - if(bars < InpMAPeriod + 2) { - Print("K线数量不足: ", bars); - return; - } - - // 限制处理的K线数量以提高性能 - int process_bars = MathMin(bars, 5000); - - if(InpShowDebugInfo) - Print("开始处理历史数据 - 总K线:", bars, ", 处理数量:", process_bars); - - // 获取价格数据 - MqlRates rates[]; - ArraySetAsSeries(rates, true); - int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, process_bars, rates); - if(copied <= 0) { - Print("复制价格数据失败"); - return; - } - - // 获取MA数据 - double ma_array[]; - ArraySetAsSeries(ma_array, true); - copied = CopyBuffer(ma_handle, 0, 0, process_bars, ma_array); - if(copied <= 0) { - Print("复制MA数据失败"); - return; - } - - if(InpShowDebugInfo) - Print("数据准备完成 - 开始识别突破K线"); - - // 识别所有突破K线 - int breakout_bars[]; - int breakout_types[]; - ArrayResize(breakout_bars, 0); - ArrayResize(breakout_types, 0); - - for(int i = process_bars - InpMAPeriod - 1; i >= 1; i--) { - int breakout_type = CheckBreakout(i, rates, ma_array); - if(breakout_type != 0) { - int size = ArraySize(breakout_bars); - ArrayResize(breakout_bars, size + 1); - ArrayResize(breakout_types, size + 1); - breakout_bars[size] = i; - breakout_types[size] = breakout_type; - } - } - - if(InpShowDebugInfo) - Print("共检测到 ", ArraySize(breakout_bars), " 个突破K线"); - - if(ArraySize(breakout_bars) == 0) { - Print("未检测到任何突破K线,请检查MA参数或数据"); - return; - } - - // 处理突破K线并标记极值点 - ProcessBreakouts(breakout_bars, breakout_types, rates); -} - -//+------------------------------------------------------------------+ -//| 检查是否是突破K线 | -//+------------------------------------------------------------------+ -int CheckBreakout(int index, const MqlRates &rates[], const double &ma[]) -{ - // 多单突破: 开盘 < MA, 收盘 > MA - if(rates[index].open < ma[index] && rates[index].close > ma[index]) - return 1; - - // 空单突破: 开盘 > MA, 收盘 < MA - if(rates[index].open > ma[index] && rates[index].close < ma[index]) - return -1; - - return 0; -} - -//+------------------------------------------------------------------+ -//| 处理所有突破K线并计算极值点 | -//+------------------------------------------------------------------+ -void ProcessBreakouts(int &breakout_bars[], int &breakout_types[], - const MqlRates &rates[]) -{ - int total = ArraySize(breakout_bars); - if(total < 2) return; - - // 过滤连续同向突破 - int filtered_bars[]; - int filtered_types[]; - ArrayResize(filtered_bars, 0); - ArrayResize(filtered_types, 0); - - for(int i = 0; i < total; i++) { - int current_bar = breakout_bars[i]; - int current_type = breakout_types[i]; - - // 检查是否有后续同向突破 - bool skip = false; - for(int j = i + 1; j < total; j++) { - if(breakout_types[j] != current_type) - break; - - if(current_type == 1) { - if(rates[breakout_bars[j]].low < rates[current_bar].low) { - skip = true; - break; - } - } else { - if(rates[breakout_bars[j]].high > rates[current_bar].high) { - skip = true; - break; - } - } - } - - if(!skip) { - int size = ArraySize(filtered_bars); - ArrayResize(filtered_bars, size + 1); - ArrayResize(filtered_types, size + 1); - filtered_bars[size] = current_bar; - filtered_types[size] = current_type; - } - } - - Print("过滤后剩余 ", ArraySize(filtered_bars), " 个有效突破K线(经过同向突破合并)"); - - // 删除旧的极值点标记 - ObjectsDeleteAll(0, "Extreme_"); - - // 计算所有极值点 - struct ExtremeInfo { - datetime time; - double price; - int type; - bool is_valid_wave; // 是否构成有效波段 - }; - - ExtremeInfo extremes[]; - ArrayResize(extremes, 0); - - // 先计算所有极值点 - for(int i = 0; i < ArraySize(filtered_bars) - 1; i++) { - int current_bar = filtered_bars[i]; - int current_type = filtered_types[i]; - int next_bar = filtered_bars[i + 1]; - - // 计算当前段的极值 - double extreme_price = 0; - datetime extreme_time = 0; - - if(current_type == 1) { - extreme_price = rates[current_bar].high; - extreme_time = rates[current_bar].time; - for(int j = current_bar; j >= next_bar; j--) { - if(rates[j].high > extreme_price) { - extreme_price = rates[j].high; - extreme_time = rates[j].time; - } - } - } else { - extreme_price = rates[current_bar].low; - extreme_time = rates[current_bar].time; - for(int j = current_bar; j >= next_bar; j--) { - if(rates[j].low < extreme_price) { - extreme_price = rates[j].low; - extreme_time = rates[j].time; - } - } - } - - // 添加到极值点数组 - int size = ArraySize(extremes); - ArrayResize(extremes, size + 1); - extremes[size].time = extreme_time; - extremes[size].price = extreme_price; - extremes[size].type = current_type; - extremes[size].is_valid_wave = false; - } - - Print("共计算出 ", ArraySize(extremes), " 个极值点"); - - // 判断哪些是有效波段 - // 策略:检查每个极值点与其前一个极值点是否能构成有效波段 - // 如果构成有效波段,则两个极值点都标记为有效 - if(ArraySize(extremes) > 0) { - // 先全部标记为无效 - for(int i = 0; i < ArraySize(extremes); i++) { - extremes[i].is_valid_wave = false; - } - - int valid_wave_count = 0; - - for(int i = 1; i < ArraySize(extremes); i++) { - // 检查与前一个极值点的价差 - double price_diff = MathAbs(extremes[i].price - extremes[i-1].price); - double price_diff_points = price_diff / _Point; - - if(InpShowDebugInfo) { - Print("检查极值点 #", i, " 与 #", i-1, " - 价差:", (int)price_diff_points, "点(", - DoubleToString(price_diff_points/100, 2), "美元)"); - } - - // 有效波段条件:与前一个极值点价差≥阈值 - if(price_diff_points >= InpWaveThreshold) { - // 标记这两个极值点都为有效波段 - extremes[i-1].is_valid_wave = true; - extremes[i].is_valid_wave = true; - valid_wave_count++; - if(InpShowDebugInfo) - Print(" ✓ 极值点 #", i-1, " 和 #", i, " 构成有效波段"); - } else { - if(InpShowDebugInfo) - Print(" ✗ 价差不足(需要", InpWaveThreshold, "点)"); - } - } - - Print(">>> 识别到 ", valid_wave_count, " 个有效波段"); - } - - // 标记所有极值点 - int valid_count = 0; - for(int i = 0; i < ArraySize(extremes); i++) { - DrawExtreme(extremes[i].time, extremes[i].price, extremes[i].type, i, extremes[i].is_valid_wave); - if(extremes[i].is_valid_wave) - valid_count++; - } - - Print("========================================"); - Print("处理完成 - 总极值点:", ArraySize(extremes), ", 有效波段极值点:", valid_count); - Print("========================================"); - ChartRedraw(); -} - -//+------------------------------------------------------------------+ -//| 在图表上绘制极值点 | -//+------------------------------------------------------------------+ -void DrawExtreme(datetime time, double price, int type, int index, bool is_valid_wave) -{ - string obj_name = "Extreme_" + IntegerToString(index); - - if(type == 1) { - // 多单突破形成的高点 - 画下箭头 - ObjectCreate(0, obj_name, OBJ_ARROW, 0, time, price); - ObjectSetInteger(0, obj_name, OBJPROP_ARROWCODE, 234); - ObjectSetInteger(0, obj_name, OBJPROP_COLOR, is_valid_wave ? InpHighExtremeColor : clrDarkRed); - ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, is_valid_wave ? 3 : 2); - ObjectSetInteger(0, obj_name, OBJPROP_ANCHOR, ANCHOR_BOTTOM); - } else { - // 空单突破形成的低点 - 画上箭头 - ObjectCreate(0, obj_name, OBJ_ARROW, 0, time, price); - ObjectSetInteger(0, obj_name, OBJPROP_ARROWCODE, 233); - ObjectSetInteger(0, obj_name, OBJPROP_COLOR, is_valid_wave ? InpLowExtremeColor : clrDarkGreen); - ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, is_valid_wave ? 3 : 2); - ObjectSetInteger(0, obj_name, OBJPROP_ANCHOR, ANCHOR_TOP); - } - - if(InpShowDebugInfo) - Print("标记极值点 #", index, " - 类型:", (type == 1 ? "高点" : "低点"), - ", 时间:", TimeToString(time), ", 价格:", DoubleToString(price, _Digits), - ", 有效波段:", (is_valid_wave ? "是" : "否")); -}