feat: 波段交易策略
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# 波段交易策略
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 ? "是" : "否"));
|
||||
}
|
||||
Reference in New Issue
Block a user