feat: 波段交易策略

This commit is contained in:
zhangyangbin
2026-05-16 16:27:09 +08:00
parent 56eb1908dc
commit dd4f6e9ce8
4 changed files with 1 additions and 652 deletions
+1
View File
@@ -0,0 +1 @@
# 波段交易策略
-306
View File
@@ -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);
}
}
-346
View File
@@ -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 ? "是" : "否"));
}