找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
首页论坛EAHub 外汇论坛
查看: 16|回复: 0

Harmonic Patterns mt5

[复制链接]

4万

主题

54

回帖

4万

积分

管理员

积分
45954
发表于 2026-8-19 03:30:00 | 显示全部楼层 |阅读模式
#property description "和谐形态交易策略 - Harmonic Patterns (Gartley, Butterfly, Crab, Bat, Cypher)"

//注意,不同的品种,一手的数量和止损要根据情况进行调整,外汇杠杆高,手数要小,股票杠杆低,可以稍大,波动止盈止损也可以根据情况调整,否则会出现成交不了的情况。





//--- 包含标准交易库
#include <Trade\Trade.mqh>

//--- 输入参数
input group "=== 和谐形态识别设置 ==="
input bool     EnableGartley = true;                    // 启用Gartley形态
input bool     EnableButterfly = true;                  // 启用Butterfly形态
input bool     EnableCrab = true;                       // 启用Crab形态
input bool     EnableBat = true;                        // 启用Bat形态
input bool     EnableCypher = true;                     // 启用Cypher形态
input int      PatternLookback = 100;                   // 形态识别回看周期
input double   FibTolerance = 0.05;                     // 斐波那契比例容差 (5%)

input group "=== 斐波那契比例设置 ==="
input double   Fib236 = 0.236;                          // 23.6%回撤
input double   Fib382 = 0.382;                          // 38.2%回撤  
input double   Fib500 = 0.500;                          // 50%回撤
input double   Fib618 = 0.618;                          // 61.8%回撤
input double   Fib786 = 0.786;                          // 78.6%回撤
input double   Fib886 = 0.886;                          // 88.6%回撤
input double   Fib1272 = 1.272;                         // 127.2%扩展
input double   Fib1618 = 1.618;                         // 161.8%扩展

input group "=== 形态验证设置 ==="
input bool     RequirePRZConfirmation = true;           // 需要潜在反转区确认
input double   PRZWidthPercent = 2.0;                   // PRZ宽度百分比
input bool     RequireRSIDivergence = true;             // 需要RSI背离确认
input int      RSIPeriod = 14;                          // RSI周期
input bool     RequireVolumeSpike = true;               // 需要成交量放量确认
input double   VolumeMultiplier = 1.5;                  // 成交量倍数

input group "=== 交易管理设置 ==="
input double   RiskRewardRatio = 2.0;                   // 风险收益比
input bool     UsePatternStops = true;                  // 使用形态止损
input bool     UseFibTargets = true;                    // 使用斐波那契目标
input int      MaxConcurrentTrades = 3;                 // 最大同时交易数
input bool     TradeOnlyPerfectPatterns = false;        // 只交易完美形态

input group "=== 风险管理 ==="
input double   RiskPercent = 1.5;                       // 风险百分比
input double   InpLotSize = 1.0;                        // 交易手数
input double   MaxStopLossPips = 100.0;                 // 最大止损点数
input double   MinRiskReward = 1.5;                     // 最小风险收益比
input bool     UseTrailingStop = true;                  // 使用跟踪止损
input double   TrailingStopPips = 40.0;                 // 跟踪止损点数

input group "=== 其他设置 ==="
input int      InpMagicNumber = 20250819;               // 魔术号码
input string   TradeComment = "HarmonicEA";             // 交易注释
input bool     ShowPatterns = true;                     // 显示形态
input bool     ShowFibLevels = true;                    // 显示斐波那契水平
input color    PatternColor = clrLimeGreen;             // 形态颜色
input color    FibColor = clrGold;                      // 斐波那契颜色

//--- 形态结构
enum ENUM_PATTERN_TYPE {
    PATTERN_GARTLEY = 0,
    PATTERN_BUTTERFLY = 1,
    PATTERN_CRAB = 2,
    PATTERN_BAT = 3,
    PATTERN_CYPHER = 4
};

struct SHarmonicPattern {
    ENUM_PATTERN_TYPE pattern_type;
    bool is_bullish;
    datetime formation_time;
    double X, A, B, C, D;                               // 5个关键点
    int X_bar, A_bar, B_bar, C_bar, D_bar;             // 对应K线索引
    double XA, AB, BC, CD;                              // 波段距离
    double AB_XA_ratio, BC_AB_ratio, CD_BC_ratio, AD_XA_ratio; // 斐波那契比例
    double prz_low, prz_high;                           // 潜在反转区
    double entry_price;                                 // 入场价格
    double stop_loss;                                   // 止损价格
    double take_profit1, take_profit2, take_profit3;    // 三个止盈目标
    bool is_valid;                                      // 形态有效性
    double pattern_quality;                             // 形态质量评分
};

//--- 全局变量
SHarmonicPattern g_current_patterns[20];
int g_pattern_count = 0;

double g_swing_highs[200];
double g_swing_lows[200];
int g_swing_high_bars[200];
int g_swing_low_bars[200];
int g_high_count = 0, g_low_count = 0;

int g_rsi_handle = INVALID_HANDLE;
double g_rsi_buffer[];

//--- 交易对象
CTrade g_trade;

//+------------------------------------------------------------------+
//| 专家初始化函数                                                      |
//+------------------------------------------------------------------+
int OnInit()
{
    Print("和谐形态策略 EA 启动");

    // 初始化交易库
    g_trade.SetExpertMagicNumber(InpMagicNumber);
    g_trade.SetMarginMode();
    g_trade.SetTypeFillingBySymbol(_Symbol);
    g_trade.SetDeviationInPoints(10);

    // 初始化RSI指标
    g_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE);
    if(g_rsi_handle == INVALID_HANDLE) {
        Print("RSI指标初始化失败");
        return INIT_FAILED;
    }

    ArraySetAsSeries(g_rsi_buffer, true);

    // 初始化摆动点数据
    if(!FindSwingPoints()) {
        Print("摆动点初始化失败");
        return INIT_FAILED;
    }

    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| 寻找摆动高低点                                                      |
//+------------------------------------------------------------------+
bool FindSwingPoints()
{
    int swing_period = 5; // 摆动点识别周期
    g_high_count = 0;
    g_low_count = 0;

    for(int i = swing_period; i < PatternLookback - swing_period; i++) {
        double high = iHigh(_Symbol, PERIOD_CURRENT, i);
        double low = iLow(_Symbol, PERIOD_CURRENT, i);

        // 识别摆动高点
        bool is_swing_high = true;
        for(int j = 1; j <= swing_period; j++) {
            if(iHigh(_Symbol, PERIOD_CURRENT, i - j) >= high ||
               iHigh(_Symbol, PERIOD_CURRENT, i + j) >= high) {
                is_swing_high = false;
                break;
            }
        }

        if(is_swing_high && g_high_count < 200) {
            g_swing_highs[g_high_count] = high;
            g_swing_high_bars[g_high_count] = i;
            g_high_count++;
        }

        // 识别摆动低点
        bool is_swing_low = true;
        for(int j = 1; j <= swing_period; j++) {
            if(iLow(_Symbol, PERIOD_CURRENT, i - j) <= low ||
               iLow(_Symbol, PERIOD_CURRENT, i + j) <= low) {
                is_swing_low = false;
                break;
            }
        }

        if(is_swing_low && g_low_count < 200) {
            g_swing_lows[g_low_count] = low;
            g_swing_low_bars[g_low_count] = i;
            g_low_count++;
        }
    }

    Print("找到摆动高点: ", g_high_count, ", 摆动低点: ", g_low_count);
    return (g_high_count >= 5 && g_low_count >= 5);
}

//+------------------------------------------------------------------+
//| 专家tick函数                                                       |
//+------------------------------------------------------------------+
void OnTick()
{
    // 更新技术指标
    if(CopyBuffer(g_rsi_handle, 0, 0, 50, g_rsi_buffer) < 50) return;

    // 重新扫描摆动点
    static datetime last_scan_time = 0;
    if(TimeCurrent() - last_scan_time > 3600) { // 每小时扫描一次
        FindSwingPoints();
        last_scan_time = TimeCurrent();
    }

    // 识别和谐形态
    ScanForHarmonicPatterns();

    // 检查交易信号
    CheckHarmonicSignals();

    // 管理现有持仓
    ManagePositions();

    // 更新图形显示
    if(ShowPatterns || ShowFibLevels) {
        UpdateChartObjects();
    }
}

//+------------------------------------------------------------------+
//| 扫描和谐形态                                                        |
//+------------------------------------------------------------------+
void ScanForHarmonicPatterns()
{
    g_pattern_count = 0;

    // 扫描看涨形态
    if(g_low_count >= 3 && g_high_count >= 2) {
        ScanBullishPatterns();
    }

    // 扫描看跌形态
    if(g_high_count >= 3 && g_low_count >= 2) {
        ScanBearishPatterns();
    }

    // 验证和评分形态
    for(int i = 0; i < g_pattern_count; i++) {
        ValidatePattern(g_current_patterns);
    }
}

//+------------------------------------------------------------------+
//| 扫描看涨形态                                                        |
//+------------------------------------------------------------------+
void ScanBullishPatterns()
{
    // 寻找 X-A-B-C-D 结构 (低-高-低-高-低)
    for(int x = 0; x < g_low_count - 2; x++) {
        for(int a = 0; a < g_high_count - 1; a++) {
            if(g_swing_high_bars[a] <= g_swing_low_bars[x]) continue;

            for(int b = x + 1; b < g_low_count - 1; b++) {
                if(g_swing_low_bars <= g_swing_high_bars[a]) continue;

                for(int c = a + 1; c < g_high_count; c++) {
                    if(g_swing_high_bars[c] <= g_swing_low_bars) continue;

                    for(int d = b + 1; d < g_low_count; d++) {
                        if(g_swing_low_bars[d] <= g_swing_high_bars[c]) continue;
                        if(g_swing_low_bars[d] < 10) continue; // 太接近当前价格

                        // 构建潜在形态
                        SHarmonicPattern pattern = {};
                        pattern.is_bullish = true;
                        pattern.X = g_swing_lows[x];
                        pattern.A = g_swing_highs[a];
                        pattern.B = g_swing_lows;
                        pattern.C = g_swing_highs[c];
                        pattern.D = g_swing_lows[d];
                        pattern.X_bar = g_swing_low_bars[x];
                        pattern.A_bar = g_swing_high_bars[a];
                        pattern.B_bar = g_swing_low_bars;
                        pattern.C_bar = g_swing_high_bars[c];
                        pattern.D_bar = g_swing_low_bars[d];

                        // 计算比例
                        CalculatePatternRatios(pattern);

                        // 识别形态类型
                        if(IdentifyPatternType(pattern) && g_pattern_count < 20) {
                            g_current_patterns[g_pattern_count] = pattern;
                            g_pattern_count++;
                        }
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 扫描看跌形态                                                        |
//+------------------------------------------------------------------+
void ScanBearishPatterns()
{
    // 寻找 X-A-B-C-D 结构 (高-低-高-低-高)
    for(int x = 0; x < g_high_count - 2; x++) {
        for(int a = 0; a < g_low_count - 1; a++) {
            if(g_swing_low_bars[a] <= g_swing_high_bars[x]) continue;

            for(int b = x + 1; b < g_high_count - 1; b++) {
                if(g_swing_high_bars <= g_swing_low_bars[a]) continue;

                for(int c = a + 1; c < g_low_count; c++) {
                    if(g_swing_low_bars[c] <= g_swing_high_bars) continue;

                    for(int d = b + 1; d < g_high_count; d++) {
                        if(g_swing_high_bars[d] <= g_swing_low_bars[c]) continue;
                        if(g_swing_high_bars[d] < 10) continue; // 太接近当前价格

                        // 构建潜在形态
                        SHarmonicPattern pattern = {};
                        pattern.is_bullish = false;
                        pattern.X = g_swing_highs[x];
                        pattern.A = g_swing_lows[a];
                        pattern.B = g_swing_highs;
                        pattern.C = g_swing_lows[c];
                        pattern.D = g_swing_highs[d];
                        pattern.X_bar = g_swing_high_bars[x];
                        pattern.A_bar = g_swing_low_bars[a];
                        pattern.B_bar = g_swing_high_bars;
                        pattern.C_bar = g_swing_low_bars[c];
                        pattern.D_bar = g_swing_high_bars[d];

                        // 计算比例
                        CalculatePatternRatios(pattern);

                        // 识别形态类型
                        if(IdentifyPatternType(pattern) && g_pattern_count < 20) {
                            g_current_patterns[g_pattern_count] = pattern;
                            g_pattern_count++;
                        }
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 计算形态比例                                                        |
//+------------------------------------------------------------------+
void CalculatePatternRatios(SHarmonicPattern &pattern)
{
    pattern.XA = MathAbs(pattern.A - pattern.X);
    pattern.AB = MathAbs(pattern.B - pattern.A);
    pattern.BC = MathAbs(pattern.C - pattern.B);
    pattern.CD = MathAbs(pattern.D - pattern.C);

    if(pattern.XA > 0) {
        pattern.AB_XA_ratio = pattern.AB / pattern.XA;
        pattern.AD_XA_ratio = MathAbs(pattern.D - pattern.A) / pattern.XA;
    }

    if(pattern.AB > 0) {
        pattern.BC_AB_ratio = pattern.BC / pattern.AB;
    }

    if(pattern.BC > 0) {
        pattern.CD_BC_ratio = pattern.CD / pattern.BC;
    }
}

//+------------------------------------------------------------------+
//| 识别形态类型                                                        |
//+------------------------------------------------------------------+
bool IdentifyPatternType(SHarmonicPattern &pattern)
{
    double tolerance = FibTolerance;

    // Gartley形态 (AB=61.8%XA, BC=38.2%-88.6%AB, CD=127.2%BC, AD=78.6%XA)
    if(EnableGartley && CheckRatio(pattern.AB_XA_ratio, Fib618, tolerance) &&
       CheckRatio(pattern.BC_AB_ratio, 0.382, tolerance, 0.886) &&
       CheckRatio(pattern.CD_BC_ratio, Fib1272, tolerance) &&
       CheckRatio(pattern.AD_XA_ratio, Fib786, tolerance)) {
        pattern.pattern_type = PATTERN_GARTLEY;
        return true;
    }

    // Butterfly形态 (AB=78.6%XA, BC=38.2%-88.6%AB, CD=161.8%BC, AD=127.2%-161.8%XA)
    if(EnableButterfly && CheckRatio(pattern.AB_XA_ratio, Fib786, tolerance) &&
       CheckRatio(pattern.BC_AB_ratio, 0.382, tolerance, 0.886) &&
       CheckRatio(pattern.CD_BC_ratio, Fib1618, tolerance) &&
       CheckRatio(pattern.AD_XA_ratio, 1.272, tolerance, 1.618)) {
        pattern.pattern_type = PATTERN_BUTTERFLY;
        return true;
    }

    // Crab形态 (AB=38.2%-61.8%XA, BC=38.2%-88.6%AB, CD=224%-361.8%BC, AD=161.8%XA)
    if(EnableCrab && CheckRatio(pattern.AB_XA_ratio, 0.382, tolerance, 0.618) &&
       CheckRatio(pattern.BC_AB_ratio, 0.382, tolerance, 0.886) &&
       CheckRatio(pattern.CD_BC_ratio, 2.24, tolerance, 3.618) &&
       CheckRatio(pattern.AD_XA_ratio, Fib1618, tolerance)) {
        pattern.pattern_type = PATTERN_CRAB;
        return true;
    }

    // Bat形态 (AB=38.2%-50%XA, BC=38.2%-88.6%AB, CD=162%-267%BC, AD=88.6%XA)
    if(EnableBat && CheckRatio(pattern.AB_XA_ratio, 0.382, tolerance, 0.50) &&
       CheckRatio(pattern.BC_AB_ratio, 0.382, tolerance, 0.886) &&
       CheckRatio(pattern.CD_BC_ratio, 1.62, tolerance, 2.67) &&
       CheckRatio(pattern.AD_XA_ratio, Fib886, tolerance)) {
        pattern.pattern_type = PATTERN_BAT;
        return true;
    }

    // Cypher形态 (AB=38.2%-61.8%XA, BC=113%-141.4%AB, CD=78.6%BC, AD=78.6%XA)
    if(EnableCypher && CheckRatio(pattern.AB_XA_ratio, 0.382, tolerance, 0.618) &&
       CheckRatio(pattern.BC_AB_ratio, 1.13, tolerance, 1.414) &&
       CheckRatio(pattern.CD_BC_ratio, Fib786, tolerance) &&
       CheckRatio(pattern.AD_XA_ratio, Fib786, tolerance)) {
        pattern.pattern_type = PATTERN_CYPHER;
        return true;
    }

    return false;
}

//+------------------------------------------------------------------+
//| 检查比例                                                           |
//+------------------------------------------------------------------+
bool CheckRatio(double actual_ratio, double target_ratio, double tolerance, double max_ratio = 0)
{
    double lower_bound = target_ratio * (1.0 - tolerance);
    double upper_bound = (max_ratio > 0) ? max_ratio * (1.0 + tolerance) : target_ratio * (1.0 + tolerance);

    return (actual_ratio >= lower_bound && actual_ratio <= upper_bound);
}

//+------------------------------------------------------------------+
//| 验证形态                                                           |
//+------------------------------------------------------------------+
void ValidatePattern(SHarmonicPattern &pattern)
{
    pattern.is_valid = false;
    pattern.pattern_quality = 0.0;

    // 计算潜在反转区 (PRZ)
    CalculatePRZ(pattern);

    // 基础有效性检查
    if(!BasicPatternValidation(pattern)) return;

    // 形态质量评分
    double quality_score = 0.0;

    // 比例精确度评分 (40%)
    quality_score += CalculateRatioAccuracy(pattern) * 0.4;

    // PRZ聚合度评分 (30%)
    quality_score += CalculatePRZQuality(pattern) * 0.3;

    // 技术指标确认评分 (20%)
    quality_score += CalculateIndicatorConfirmation(pattern) * 0.2;

    // 成交量确认评分 (10%)
    quality_score += CalculateVolumeConfirmation(pattern) * 0.1;

    pattern.pattern_quality = quality_score;

    // 设置质量阈值
    double min_quality = TradeOnlyPerfectPatterns ? 0.8 : 0.6;
    pattern.is_valid = (quality_score >= min_quality);

    if(pattern.is_valid) {
        CalculateTradeParameters(pattern);
    }
}

//+------------------------------------------------------------------+
//| 计算潜在反转区                                                      |
//+------------------------------------------------------------------+
void CalculatePRZ(SHarmonicPattern &pattern)
{
    double prz_width = MathAbs(pattern.A - pattern.X) * PRZWidthPercent / 100.0;

    if(pattern.is_bullish) {
        pattern.prz_low = pattern.D - prz_width / 2;
        pattern.prz_high = pattern.D + prz_width / 2;
    } else {
        pattern.prz_low = pattern.D - prz_width / 2;
        pattern.prz_high = pattern.D + prz_width / 2;
    }
}

//+------------------------------------------------------------------+
//| 基础形态验证                                                        |
//+------------------------------------------------------------------+
bool BasicPatternValidation(const SHarmonicPattern &pattern)
{
    // 时间序列检查
    if(pattern.X_bar <= pattern.A_bar || pattern.A_bar <= pattern.B_bar ||
       pattern.B_bar <= pattern.C_bar || pattern.C_bar <= pattern.D_bar) {
        return false;
    }

    // 价格结构检查
    if(pattern.is_bullish) {
        if(pattern.X >= pattern.A || pattern.B >= pattern.A ||
           pattern.C <= pattern.B || pattern.D >= pattern.C) {
            return false;
        }
    } else {
        if(pattern.X <= pattern.A || pattern.B <= pattern.A ||
           pattern.C >= pattern.B || pattern.D <= pattern.C) {
            return false;
        }
    }

    return true;
}

//+------------------------------------------------------------------+
//| 计算比例精确度                                                      |
//+------------------------------------------------------------------+
double CalculateRatioAccuracy(const SHarmonicPattern &pattern)
{
    double total_accuracy = 0.0;
    int ratio_count = 0;

    // 根据形态类型计算各比例的精确度
    switch(pattern.pattern_type) {
        case PATTERN_GARTLEY:
            total_accuracy += 1.0 - MathAbs(pattern.AB_XA_ratio - Fib618) / Fib618;
            total_accuracy += 1.0 - MathAbs(pattern.AD_XA_ratio - Fib786) / Fib786;
            ratio_count = 2;
            break;
        case PATTERN_BUTTERFLY:
            total_accuracy += 1.0 - MathAbs(pattern.AB_XA_ratio - Fib786) / Fib786;
            total_accuracy += 1.0 - MathAbs(pattern.CD_BC_ratio - Fib1618) / Fib1618;
            ratio_count = 2;
            break;
        case PATTERN_CRAB:
            total_accuracy += 1.0 - MathAbs(pattern.AD_XA_ratio - Fib1618) / Fib1618;
            ratio_count = 1;
            break;
        case PATTERN_BAT:
            total_accuracy += 1.0 - MathAbs(pattern.AD_XA_ratio - Fib886) / Fib886;
            ratio_count = 1;
            break;
        case PATTERN_CYPHER:
            total_accuracy += 1.0 - MathAbs(pattern.AD_XA_ratio - Fib786) / Fib786;
            ratio_count = 1;
            break;
    }

    return ratio_count > 0 ? MathMax(0.0, total_accuracy / ratio_count) : 0.0;
}

//+------------------------------------------------------------------+
//| 计算PRZ质量                                                        |
//+------------------------------------------------------------------+
double CalculatePRZQuality(const SHarmonicPattern &pattern)
{
    double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double prz_center = (pattern.prz_high + pattern.prz_low) / 2.0;
    double distance_to_prz = MathAbs(current_price - prz_center);
    double prz_width = pattern.prz_high - pattern.prz_low;

    // 价格越接近PRZ中心,质量评分越高
    return MathMax(0.0, 1.0 - (distance_to_prz / prz_width));
}

//+------------------------------------------------------------------+
//| 计算指标确认                                                        |
//+------------------------------------------------------------------+
double CalculateIndicatorConfirmation(const SHarmonicPattern &pattern)
{
    double confirmation = 0.0;

    if(RequireRSIDivergence && ArraySize(g_rsi_buffer) > pattern.D_bar + 5) {
        // 检查RSI背离
        double rsi_at_d = g_rsi_buffer[pattern.D_bar];
        double rsi_current = g_rsi_buffer[0];

        if(pattern.is_bullish) {
            // 看涨背离:价格创新低,RSI不创新低
            if(pattern.D < pattern.B && rsi_at_d > g_rsi_buffer[pattern.B_bar]) {
                confirmation += 0.5;
            }
            // RSI超卖确认
            if(rsi_current < 30) {
                confirmation += 0.3;
            }
        } else {
            // 看跌背离:价格创新高,RSI不创新高
            if(pattern.D > pattern.B && rsi_at_d < g_rsi_buffer[pattern.B_bar]) {
                confirmation += 0.5;
            }
            // RSI超买确认
            if(rsi_current > 70) {
                confirmation += 0.3;
            }
        }
    }

    return MathMin(1.0, confirmation);
}

//+------------------------------------------------------------------+
//| 计算成交量确认                                                      |
//+------------------------------------------------------------------+
double CalculateVolumeConfirmation(const SHarmonicPattern &pattern)
{
    if(!RequireVolumeSpike) return 1.0;

    long volume_at_d = iVolume(_Symbol, PERIOD_CURRENT, pattern.D_bar);
    long avg_volume = 0;

    for(int i = pattern.D_bar + 1; i <= pattern.D_bar + 20; i++) {
        avg_volume += iVolume(_Symbol, PERIOD_CURRENT, i);
    }
    avg_volume /= 20;

    if(avg_volume > 0) {
        double volume_ratio = (double)volume_at_d / avg_volume;
        return MathMin(1.0, volume_ratio / VolumeMultiplier);
    }

    return 0.5;
}

//+------------------------------------------------------------------+
//| 计算交易参数                                                        |
//+------------------------------------------------------------------+
void CalculateTradeParameters(SHarmonicPattern &pattern)
{
    pattern.entry_price = pattern.D;

    // 计算止损
    if(UsePatternStops) {
        double pattern_range = MathAbs(pattern.A - pattern.X);
        double stop_distance = pattern_range * 0.1; // 10%的形态范围

        if(pattern.is_bullish) {
            pattern.stop_loss = pattern.D - stop_distance;
        } else {
            pattern.stop_loss = pattern.D + stop_distance;
        }
    } else {
        double stop_distance = MaxStopLossPips * Point();
        if(pattern.is_bullish) {
            pattern.stop_loss = pattern.D - stop_distance;
        } else {
            pattern.stop_loss = pattern.D + stop_distance;
        }
    }

    // 计算止盈目标
    if(UseFibTargets) {
        double cd_range = MathAbs(pattern.D - pattern.C);

        if(pattern.is_bullish) {
            pattern.take_profit1 = pattern.D + cd_range * Fib382;
            pattern.take_profit2 = pattern.D + cd_range * Fib618;
            pattern.take_profit3 = pattern.D + cd_range * Fib786;
        } else {
            pattern.take_profit1 = pattern.D - cd_range * Fib382;
            pattern.take_profit2 = pattern.D - cd_range * Fib618;
            pattern.take_profit3 = pattern.D - cd_range * Fib786;
        }
    } else {
        double stop_distance = MathAbs(pattern.entry_price - pattern.stop_loss);

        if(pattern.is_bullish) {
            pattern.take_profit1 = pattern.entry_price + stop_distance * RiskRewardRatio;
            pattern.take_profit2 = pattern.entry_price + stop_distance * RiskRewardRatio * 1.5;
            pattern.take_profit3 = pattern.entry_price + stop_distance * RiskRewardRatio * 2.0;
        } else {
            pattern.take_profit1 = pattern.entry_price - stop_distance * RiskRewardRatio;
            pattern.take_profit2 = pattern.entry_price - stop_distance * RiskRewardRatio * 1.5;
            pattern.take_profit3 = pattern.entry_price - stop_distance * RiskRewardRatio * 2.0;
        }
    }
}

//+------------------------------------------------------------------+
//| 检查和谐信号                                                        |
//+------------------------------------------------------------------+
void CheckHarmonicSignals()
{
    double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    for(int i = 0; i < g_pattern_count; i++) {
        if(!g_current_patterns.is_valid) continue;
        if(g_current_patterns.D_bar > 5) continue; // 只交易最新的形态

        // 检查价格是否到达D点附近
        double distance_to_d = MathAbs(current_price - g_current_patterns.D);
        double entry_tolerance = Point() * 10;

        if(distance_to_d <= entry_tolerance && PositionsTotal() < MaxConcurrentTrades) {
            // 最后确认
            if(RequirePRZConfirmation) {
                if(current_price < g_current_patterns.prz_low ||
                   current_price > g_current_patterns.prz_high) {
                    continue;
                }
            }

            ExecuteHarmonicTrade(g_current_patterns);
        }
    }
}

//+------------------------------------------------------------------+
//| 执行和谐交易                                                        |
//+------------------------------------------------------------------+
void ExecuteHarmonicTrade(const SHarmonicPattern &pattern)
{
    double volume = CalculateLotSize(pattern);
    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    // 规范化交易量
    double min_vol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    double max_vol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
    double vol_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

    // 确保交易量符合要求
    volume = MathMax(volume, min_vol);
    volume = MathMin(volume, max_vol);
    volume = MathRound(volume / vol_step) * vol_step;

    string pattern_name = GetPatternName(pattern.pattern_type);
    Print("交易量信息: 输入=", InpLotSize, " 最小=", min_vol, " 最大=", max_vol, " 步长=", vol_step, " 最终=", volume);

    string comment = TradeComment + " " + pattern_name + (pattern.is_bullish ? " Buy" : " Sell");

    bool trade_result = false;
    if(pattern.is_bullish) {
        trade_result = g_trade.Buy(volume, _Symbol, ask, pattern.stop_loss, pattern.take_profit1, comment);
    } else {
        trade_result = g_trade.Sell(volume, _Symbol, bid, pattern.stop_loss, pattern.take_profit1, comment);
    }

    if(trade_result) {
        Print("和谐形态交易执行成功: ", pattern_name, " 质量评分: ", pattern.pattern_quality, " 交易量: ", volume);
    } else {
        Print("和谐形态交易执行失败: ", g_trade.ResultRetcode(), " - ", g_trade.ResultComment());
    }
}

//+------------------------------------------------------------------+
//| 获取形态名称                                                        |
//+------------------------------------------------------------------+
string GetPatternName(ENUM_PATTERN_TYPE pattern_type)
{
    switch(pattern_type) {
        case PATTERN_GARTLEY: return "Gartley";
        case PATTERN_BUTTERFLY: return "Butterfly";
        case PATTERN_CRAB: return "Crab";
        case PATTERN_BAT: return "Bat";
        case PATTERN_CYPHER: return "Cypher";
        default: return "Unknown";
    }
}

//+------------------------------------------------------------------+
//| 计算仓位大小                                                        |
//+------------------------------------------------------------------+
double CalculateLotSize(const SHarmonicPattern &pattern)
{
    // 使用固定交易量与风险管理结合
    double base_volume = InpLotSize;

    // 根据风险管理调整
    if(RiskPercent > 0) {
        double account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
        double risk_amount = account_balance * RiskPercent / 100.0;
        double stop_distance = MathAbs(pattern.entry_price - pattern.stop_loss);
        double pip_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);

        if(pip_value > 0 && stop_distance > 0) {
            double pips_at_risk = stop_distance / Point();
            double calculated_size = risk_amount / (pips_at_risk * pip_value);
            base_volume = MathMin(base_volume, calculated_size);
        }
    }

    return MathMax(0.01, NormalizeDouble(base_volume, 2));
}

//+------------------------------------------------------------------+
//| 管理现有持仓                                                        |
//+------------------------------------------------------------------+
void ManagePositions()
{
    for(int i = 0; i < PositionsTotal(); i++) {
        ulong ticket = PositionGetTicket(i);
        if(ticket == 0 || PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;

        if(UseTrailingStop) {
            UpdateTrailingStop(ticket);
        }

        // 检查部分止盈
        CheckPartialProfitTarget(ticket);
    }
}

//+------------------------------------------------------------------+
//| 更新跟踪止损                                                        |
//+------------------------------------------------------------------+
void UpdateTrailingStop(ulong ticket)
{
    if(!PositionSelectByTicket(ticket)) return;

    double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
    double current_sl = PositionGetDouble(POSITION_SL);
    long position_type = PositionGetInteger(POSITION_TYPE);
    double current_price = position_type == POSITION_TYPE_BUY ?
                          SymbolInfoDouble(_Symbol, SYMBOL_BID) :
                          SymbolInfoDouble(_Symbol, SYMBOL_ASK);

    double trailing_distance = TrailingStopPips * Point();
    double new_sl = 0;

    if(position_type == POSITION_TYPE_BUY) {
        new_sl = current_price - trailing_distance;
        if(new_sl > current_sl && new_sl > position_open_price) {
            ModifyPosition(ticket, new_sl, PositionGetDouble(POSITION_TP));
        }
    } else {
        new_sl = current_price + trailing_distance;
        if((current_sl == 0 || new_sl < current_sl) && new_sl < position_open_price) {
            ModifyPosition(ticket, new_sl, PositionGetDouble(POSITION_TP));
        }
    }
}

//+------------------------------------------------------------------+
//| 检查部分止盈目标                                                     |
//+------------------------------------------------------------------+
void CheckPartialProfitTarget(ulong ticket)
{
    // 可以实现多目标止盈逻辑
    // 这里简化处理,实际可以根据形态的多个止盈目标来分批平仓
}

//+------------------------------------------------------------------+
//| 修改持仓                                                           |
//+------------------------------------------------------------------+
bool ModifyPosition(ulong ticket, double sl, double tp)
{
    return g_trade.PositionModify(ticket, NormalizeDouble(sl, _Digits), NormalizeDouble(tp, _Digits));
}

//+------------------------------------------------------------------+
//| 更新图表对象                                                        |
//+------------------------------------------------------------------+
void UpdateChartObjects()
{
    if(!ShowPatterns && !ShowFibLevels) return;

    for(int i = 0; i < g_pattern_count; i++) {
        if(!g_current_patterns.is_valid) continue;

        DrawHarmonicPattern(g_current_patterns, i);
    }
}

//+------------------------------------------------------------------+
//| 绘制和谐形态                                                        |
//+------------------------------------------------------------------+
void DrawHarmonicPattern(const SHarmonicPattern &pattern, int pattern_index)
{
    string pattern_prefix = "Harmonic_" + IntegerToString(pattern_index) + "_";
    color line_color = pattern.is_bullish ? clrLimeGreen : clrRed;

    // 绘制XABCD连线
    datetime x_time = iTime(_Symbol, PERIOD_CURRENT, pattern.X_bar);
    datetime a_time = iTime(_Symbol, PERIOD_CURRENT, pattern.A_bar);
    datetime b_time = iTime(_Symbol, PERIOD_CURRENT, pattern.B_bar);
    datetime c_time = iTime(_Symbol, PERIOD_CURRENT, pattern.C_bar);
    datetime d_time = iTime(_Symbol, PERIOD_CURRENT, pattern.D_bar);

    // XA线
    ObjectDelete(0, pattern_prefix + "XA");
    ObjectCreate(0, pattern_prefix + "XA", OBJ_TREND, 0, x_time, pattern.X, a_time, pattern.A);
    ObjectSetInteger(0, pattern_prefix + "XA", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "XA", OBJPROP_WIDTH, 2);

    // AB线
    ObjectDelete(0, pattern_prefix + "AB");
    ObjectCreate(0, pattern_prefix + "AB", OBJ_TREND, 0, a_time, pattern.A, b_time, pattern.B);
    ObjectSetInteger(0, pattern_prefix + "AB", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "AB", OBJPROP_WIDTH, 2);

    // BC线
    ObjectDelete(0, pattern_prefix + "BC");
    ObjectCreate(0, pattern_prefix + "BC", OBJ_TREND, 0, b_time, pattern.B, c_time, pattern.C);
    ObjectSetInteger(0, pattern_prefix + "BC", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "BC", OBJPROP_WIDTH, 2);

    // CD线
    ObjectDelete(0, pattern_prefix + "CD");
    ObjectCreate(0, pattern_prefix + "CD", OBJ_TREND, 0, c_time, pattern.C, d_time, pattern.D);
    ObjectSetInteger(0, pattern_prefix + "CD", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "CD", OBJPROP_WIDTH, 2);

    // 对角线XB和AC
    ObjectDelete(0, pattern_prefix + "XB");
    ObjectCreate(0, pattern_prefix + "XB", OBJ_TREND, 0, x_time, pattern.X, b_time, pattern.B);
    ObjectSetInteger(0, pattern_prefix + "XB", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "XB", OBJPROP_STYLE, STYLE_DOT);

    ObjectDelete(0, pattern_prefix + "AC");
    ObjectCreate(0, pattern_prefix + "AC", OBJ_TREND, 0, a_time, pattern.A, c_time, pattern.C);
    ObjectSetInteger(0, pattern_prefix + "AC", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "AC", OBJPROP_STYLE, STYLE_DOT);

    // 绘制PRZ区域
    ObjectDelete(0, pattern_prefix + "RZ");
    ObjectCreate(0, pattern_prefix + "RZ", OBJ_RECTANGLE, 0,
                d_time, pattern.prz_low, TimeCurrent() + 3600, pattern.prz_high);
    ObjectSetInteger(0, pattern_prefix + "RZ", OBJPROP_COLOR, clrYellow);
    ObjectSetInteger(0, pattern_prefix + "RZ", OBJPROP_STYLE, STYLE_SOLID);
    ObjectSetInteger(0, pattern_prefix + "RZ", OBJPROP_FILL, true);
    ObjectSetInteger(0, pattern_prefix + "RZ", OBJPROP_BACK, true);

    // 添加文本标签
    string pattern_name = GetPatternName(pattern.pattern_type);
    string label_text = pattern_name + (pattern.is_bullish ? " 看涨" : " 看跌") +
                       " 质量: " + DoubleToString(pattern.pattern_quality, 2);

    ObjectDelete(0, pattern_prefix + "Label");
    ObjectCreate(0, pattern_prefix + "Label", OBJ_TEXT, 0, d_time, pattern.D);
    ObjectSetString(0, pattern_prefix + "Label", OBJPROP_TEXT, label_text);
    ObjectSetInteger(0, pattern_prefix + "Label", OBJPROP_COLOR, line_color);
    ObjectSetInteger(0, pattern_prefix + "Label", OBJPROP_FONTSIZE, 8);
}

//+------------------------------------------------------------------+
//| 专家反初始化函数                                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // 释放指标句柄
    if(g_rsi_handle != INVALID_HANDLE) {
        IndicatorRelease(g_rsi_handle);
    }

    // 清理图表对象
    ObjectsDeleteAll(0, "Harmonic_");

    Print("和谐形态策略 EA 已停止,原因代码: ", reason);
}
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|EAHub外汇论坛

GMT+8, 2026-10-10 02:32 , Processed in 0.109535 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表