forked from ntsinh90/EA_SMC_Mql5
855 lines
No EOL
86 KiB
MQL5
855 lines
No EOL
86 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| CEntryExecutor.mqh |
|
|
//| v35.0 - Final Unified Strategy Engine |
|
|
//+------------------------------------------------------------------+
|
|
#ifndef CENTRYEXECUTOR_MQH
|
|
#define CENTRYEXECUTOR_MQH
|
|
|
|
#include "CEnumSharing.mqh"
|
|
#include "CZoneManager.mqh"
|
|
#include "CStructureAnalyzer.mqh"
|
|
#include "SMC_DataStructures.mqh"
|
|
|
|
class CEntryExecutor {
|
|
private:
|
|
CZoneManager* m_zone_manager_ptr;
|
|
CStructureAnalyzer* m_analyzer_ptr;
|
|
int m_max_trades_per_zone;
|
|
|
|
// Toggles for each independent strategy
|
|
bool m_use_continuation_retest;
|
|
bool m_use_reversal_retest;
|
|
bool m_use_breakout_entry;
|
|
bool m_use_fakeout_entry;
|
|
bool m_use_major_swing_momentum_entry;
|
|
bool m_use_sfp_entry;
|
|
bool m_use_sweep_and_poi_entry;
|
|
bool m_use_scale_in_on_breakout;
|
|
bool m_use_fresh_fvg_retest_entry;
|
|
|
|
// Toggles for retest confirmation patterns
|
|
bool m_use_simple_reclaim_pattern;
|
|
bool m_use_2_bar_confirmation;
|
|
bool m_use_3_bar_confirmation;
|
|
|
|
// Toggles for specific exit conditions
|
|
int m_breakout_retest_number;
|
|
|
|
// Toggles for Stochastic entry confirmation
|
|
bool m_use_sto_for_entry_confirmation;
|
|
int m_sto_overbought;
|
|
int m_sto_oversold;
|
|
|
|
// Toggles for advanced FVG retest confirmation
|
|
ENUM_RETEST_CONFIRMATION_MODE m_retest_confirmation_mode;
|
|
double m_retest_min_atr_moveaway;
|
|
|
|
SwingPoint* GetPreviousSwing(int start_index, ENUM_SWING_TYPE type_to_find, CArrayObj* swings_all)
|
|
{
|
|
if(start_index <= 0 || swings_all == NULL) return NULL;
|
|
for(int i = start_index - 1; i >= 0; i--) {
|
|
SwingPoint *swing = swings_all.At(i);
|
|
if(swing != NULL && swing.status != STATUS_NOISE && swing.type == type_to_find) {
|
|
return swing;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// --- UPDATED with deep diagnostics ---
|
|
bool IsStoInExtremeZone(int start_idx, int end_idx, ENUM_DIRECTION direction, CDataContext &context)
|
|
{
|
|
// ถ้าปิดฟิลเตอร์นี้ ให้ถือว่าผ่านเสมอ
|
|
if(!m_use_sto_for_entry_confirmation) return true;
|
|
|
|
PrintFormat("--- [Sto Check] Looking for %s signal in %d-bar window...", EnumToString(direction), (end_idx - start_idx + 1));
|
|
|
|
bool primary_condition_met = false;
|
|
datetime triggering_time = 0;
|
|
double triggering_sto_value = 0.0;
|
|
|
|
// --- 1. ตรวจสอบว่ามีแท่งเทียนใดๆ ในกรอบเวลาที่เข้าเงื่อนไขหลักหรือไม่ (Primary Condition) ---
|
|
for(int i = start_idx; i <= end_idx; i++) {
|
|
if(i < 0 || i >= context.bars_to_load) continue;
|
|
|
|
double sto_value = context.sto_main_buffer[i];
|
|
if(direction == DIRECTION_BULLISH && sto_value <= m_sto_oversold) {
|
|
primary_condition_met = true;
|
|
triggering_time = context.rates[i].time;
|
|
triggering_sto_value = sto_value;
|
|
break; // เจอแล้ว ไม่ต้องหาต่อ
|
|
}
|
|
if(direction == DIRECTION_BEARISH && sto_value >= m_sto_overbought) {
|
|
primary_condition_met = true;
|
|
triggering_time = context.rates[i].time;
|
|
triggering_sto_value = sto_value;
|
|
break; // เจอแล้ว ไม่ต้องหาต่อ
|
|
}
|
|
}
|
|
|
|
if(!primary_condition_met) {
|
|
Print(" - [Primary Check]: FAILED. No candle in window met OB/OS condition.");
|
|
return false;
|
|
} else {
|
|
PrintFormat(" - [Primary Check]: PASSED. Triggered by candle at %s with Sto value: %.2f",
|
|
TimeToString(triggering_time), triggering_sto_value);
|
|
}
|
|
|
|
// --- 2. ถ้าเงื่อนไขหลักผ่าน ให้มาตรวจสอบเงื่อนไข "Veto" ที่แท่งยืนยันสุดท้าย ---
|
|
// แท่งยืนยันสุดท้ายคือแท่งที่ index = 1 เสมอ
|
|
double confirmation_candle_sto = context.sto_main_buffer[1];
|
|
bool veto_condition_met = false;
|
|
|
|
if(direction == DIRECTION_BULLISH && confirmation_candle_sto >= m_sto_overbought) {
|
|
// กำลังจะ Buy แต่แท่งยืนยันกลับ Overbought . สัญญาณอันตราย, ใช้สิทธิ์ Veto
|
|
veto_condition_met = true;
|
|
}
|
|
else if(direction == DIRECTION_BEARISH && confirmation_candle_sto <= m_sto_oversold) {
|
|
// กำลังจะ Sell แต่แท่งยืนยันกลับ Oversold . สัญญาณอันตราย, ใช้สิทธิ์ Veto
|
|
veto_condition_met = true;
|
|
}
|
|
|
|
if(veto_condition_met) {
|
|
PrintFormat(" - [Veto Check]: FAILED. Confirmation candle Sto (%.2f) is in opposite extreme zone.", confirmation_candle_sto);
|
|
} else {
|
|
PrintFormat(" - [Veto Check]: PASSED. Confirmation candle Sto (%.2f) is not in opposite zone.", confirmation_candle_sto);
|
|
}
|
|
|
|
// --- 3. สรุปผลสุดท้าย ---
|
|
bool final_result = (primary_condition_met && !veto_condition_met);
|
|
PrintFormat(" >>> Final Sto Filter Result: %s", (string)final_result);
|
|
return final_result;
|
|
}
|
|
|
|
bool IsSimpleReclaimPattern(CDataContext &context, CSignalZone* zone)
|
|
{
|
|
if(zone == NULL || ArraySize(context.rates) < 2) return false;
|
|
MqlRates last_bar = context.rates[1];
|
|
|
|
if(zone.direction == DIRECTION_BULLISH) {
|
|
bool retested = last_bar.low <= zone.top;
|
|
bool is_bullish_candle = last_bar.close > last_bar.open;
|
|
bool closed_above_zone = last_bar.close > zone.top;
|
|
bool pattern_ok = (retested && is_bullish_candle && closed_above_zone); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
|
|
// Final Check: Stochastic Confirmation
|
|
return IsStoInExtremeZone(1, 1, zone.direction, context);
|
|
}
|
|
else if(zone.direction == DIRECTION_BEARISH) {
|
|
bool retested = last_bar.high >= zone.bottom;
|
|
bool is_bearish_candle = last_bar.close < last_bar.open;
|
|
bool closed_below_zone = last_bar.close < zone.bottom;
|
|
bool pattern_ok = (retested && is_bearish_candle && closed_below_zone);
|
|
if(!pattern_ok) return false;
|
|
|
|
// Final Check: Stochastic Confirmation
|
|
return IsStoInExtremeZone(1, 1, zone.direction, context);
|
|
}
|
|
return false;
|
|
}
|
|
// --- Reusable Candle Pattern Library ---
|
|
bool Is2BarPowerCandle(CDataContext &context, CSignalZone* zone)
|
|
{
|
|
if(zone == NULL || ArraySize(context.rates) < 3) return false;
|
|
MqlRates last_bar = context.rates[1];
|
|
MqlRates prev_bar = context.rates[2];
|
|
|
|
if(zone.direction == DIRECTION_BULLISH) {
|
|
bool retested = prev_bar.low <= zone.top;
|
|
if(!retested) return false;
|
|
bool is_bar1_bullish = last_bar.close > last_bar.open;
|
|
double body1 = MathAbs(last_bar.close - last_bar.open);
|
|
double body2 = MathAbs(prev_bar.close - prev_bar.open);
|
|
bool bar1_closed_above = last_bar.close > zone.top;
|
|
bool bar1_is_power_candle = (body2 > 0) ? (body1 > (body2 * 2.0)) : (body1 > 0);
|
|
bool pattern_ok = (is_bar1_bullish && bar1_closed_above && bar1_is_power_candle); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
|
|
// Final Check: Stochastic Confirmation over a 2-bar window
|
|
return IsStoInExtremeZone(1, 2, zone.direction, context);
|
|
}
|
|
else if(zone.direction == DIRECTION_BEARISH) {
|
|
bool retested = prev_bar.high >= zone.bottom;
|
|
if(!retested) return false;
|
|
bool is_bar1_bearish = last_bar.close < last_bar.open;
|
|
double body1 = MathAbs(last_bar.close - last_bar.open);
|
|
double body2 = MathAbs(prev_bar.close - prev_bar.open);
|
|
bool bar1_closed_below = last_bar.close < zone.bottom;
|
|
bool bar1_is_power_candle = (body2 > 0) ? (body1 > (body2 * 2.0)) : (body1 > 0);
|
|
bool pattern_ok = (is_bar1_bearish && bar1_closed_below && bar1_is_power_candle); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
|
|
// Final Check: Stochastic Confirmation over a 2-bar window
|
|
return IsStoInExtremeZone(1, 2, zone.direction, context);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Candle_Engulfing(CDataContext &context, ENUM_DIRECTION direction)
|
|
{
|
|
if(ArraySize(context.rates) < 3) return false;
|
|
MqlRates last_bar = context.rates[1];
|
|
MqlRates prev_bar = context.rates[2];
|
|
|
|
if(direction == DIRECTION_BULLISH) {
|
|
bool is_bar1_bullish = last_bar.close > last_bar.open;
|
|
double body1 = MathAbs(last_bar.close - last_bar.open);
|
|
double body2 = MathAbs(prev_bar.close - prev_bar.open);
|
|
bool bar1_is_power_candle = (body2 > 0) ? (body1 > (body2 * 2.0)) : (body1 > 0);
|
|
bool pattern_ok = (is_bar1_bullish && bar1_is_power_candle); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
return true;
|
|
}
|
|
else if(direction == DIRECTION_BEARISH) {
|
|
bool is_bar1_bearish = last_bar.close < last_bar.open;
|
|
double body1 = MathAbs(last_bar.close - last_bar.open);
|
|
double body2 = MathAbs(prev_bar.close - prev_bar.open);
|
|
bool bar1_is_power_candle = (body2 > 0) ? (body1 > (body2 * 2.0)) : (body1 > 0);
|
|
bool pattern_ok = (is_bar1_bearish && bar1_is_power_candle); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Is3BarReversal(CDataContext &context, CSignalZone* zone)
|
|
{
|
|
if(zone == NULL || ArraySize(context.rates) < 4) return false;
|
|
|
|
if(zone.direction == DIRECTION_BULLISH) {
|
|
bool isRetesting = (context.rates[1].low <= zone.top) || (context.rates[2].low <= zone.top) || (context.rates[3].low <= zone.top);
|
|
bool bar3_valid = (context.rates[3].open > context.rates[3].close) && (context.rates[3].close > zone.top);
|
|
bool bar2_valid = (context.rates[2].open < context.rates[2].close) && (context.rates[2].close > zone.top);
|
|
double highest_point = MathMax(context.rates[2].high, context.rates[3].high);
|
|
bool bar1_valid = (context.rates[1].open < context.rates[1].close) && (context.rates[1].close > highest_point);
|
|
|
|
bool pattern_ok = (isRetesting && bar3_valid && bar2_valid && bar1_valid); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
|
|
// Final Check: Stochastic Confirmation over a 3-bar window
|
|
return IsStoInExtremeZone(1, 3, zone.direction, context);
|
|
}
|
|
else if(zone.direction == DIRECTION_BEARISH) {
|
|
bool isRetesting = (context.rates[1].high >= zone.bottom) || (context.rates[2].high >= zone.bottom) || (context.rates[3].high >= zone.bottom);
|
|
bool bar3_valid = (context.rates[3].open < context.rates[3].close) && (context.rates[3].close < zone.bottom);
|
|
bool bar2_valid = (context.rates[2].open > context.rates[2].close) && (context.rates[2].close < zone.bottom);
|
|
double lowest_point = MathMin(context.rates[2].low, context.rates[3].low);
|
|
bool bar1_valid = (context.rates[1].open > context.rates[1].close) && (context.rates[1].close < lowest_point);
|
|
bool pattern_ok = (isRetesting && bar3_valid && bar2_valid && bar1_valid); // for bullish case
|
|
if(!pattern_ok) return false;
|
|
|
|
// Final Check: Stochastic Confirmation over a 3-bar window
|
|
return IsStoInExtremeZone(1, 3, zone.direction, context);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// --- Strategy: First Touch on a Fresh FVG (Detective Version) ---
|
|
CSignalZone* CheckForFreshFvgRetest(CDataContext &context)
|
|
{
|
|
if(ArraySize(context.rates) < 2) return NULL;
|
|
CArrayObj* zone_list = m_zone_manager_ptr.GetSignificantZones();
|
|
if(zone_list == NULL) return NULL;
|
|
|
|
for(int i = 0; i < zone_list.Total(); i++)
|
|
{
|
|
CSignalZone* zone = zone_list.At(i);
|
|
|
|
// --- ด่านที่ 1: ตรวจสอบคุณสมบัติพื้นฐานของโซน ---
|
|
if(zone == NULL || zone.zone_type != ZONE_FVG || !zone.is_significant || zone.state == STATE_INVALIDATED) {
|
|
continue;
|
|
}
|
|
|
|
// --- เริ่มการดีบักสำหรับโซนที่น่าสนใจ ---
|
|
PrintFormat("--- [Fresh FVG Check] Grading zone at %s...", TimeToString(zone.time));
|
|
|
|
// ด่าน 1.1: เช็ค Blacklist
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(zone.time);
|
|
if(level_info != NULL && level_info.trade_count >= m_max_trades_per_zone) {
|
|
Print(" - REJECTED: Already traded max times for this level.");
|
|
continue;
|
|
}
|
|
|
|
// ด่าน 1.2: เช็คครั้งที่ของการรีเทส (Nth Retest)
|
|
// ถ้า m_breakout_retest_number = 1, เราจะมองหาโซนที่ mitigation_count = 0
|
|
if(m_breakout_retest_number > 0 && zone.mitigation_count != (m_breakout_retest_number - 1)) {
|
|
PrintFormat(" - REJECTED: Incorrect mitigation count. Is: %d, Required: %d", zone.mitigation_count, m_breakout_retest_number - 1);
|
|
continue;
|
|
}
|
|
PrintFormat(" - PASSED: Initial checks (Significant, FVG, Not traded, Correct mitigation count).");
|
|
|
|
// --- ด่านที่ 2: ตรวจสอบการยืนยันการออกจากพื้นที่ (Move Away Confirmation) ---
|
|
bool confirmation_passed = false;
|
|
PrintFormat(" - Checking Move Away Confirmation (Mode: %s)...", EnumToString(m_retest_confirmation_mode));
|
|
PrintFormat(" - Zone state: Has Displacement? %s, Has Structure Confirmation? %s", (string)zone.has_displacement, (string)zone.has_structure_confirmation);
|
|
|
|
switch(m_retest_confirmation_mode)
|
|
{
|
|
case CONF_MODE_NONE: confirmation_passed = true; break;
|
|
case CONF_MODE_DISPLACEMENT_ONLY: confirmation_passed = zone.has_displacement; break;
|
|
case CONF_MODE_STRUCTURE_ONLY: confirmation_passed = zone.has_structure_confirmation; break;
|
|
case CONF_MODE_DISP_AND_STRUCT: confirmation_passed = (zone.has_displacement && zone.has_structure_confirmation); break;
|
|
}
|
|
|
|
if(!confirmation_passed) {
|
|
Print(" - REJECTED: Failed Move Away Confirmation check.");
|
|
continue;
|
|
}
|
|
Print(" - PASSED: Move Away Confirmation.");
|
|
|
|
// --- ด่านที่ 3: ตรวจสอบการรีเทส (The Actual Retest Trigger) ---
|
|
MqlRates last_bar = context.rates[1];
|
|
bool is_touching_now = false;
|
|
if(zone.direction == DIRECTION_BULLISH && last_bar.low <= zone.top) is_touching_now = true;
|
|
else if (zone.direction == DIRECTION_BEARISH && last_bar.high >= zone.bottom) is_touching_now = true;
|
|
|
|
if(!is_touching_now) {
|
|
// ไม่ใช่บั๊ก แค่ราคายังไม่มาถึง ไม่ต้อง Print ก็ได้เพื่อไม่ให้ Log รก
|
|
continue;
|
|
}
|
|
Print(" - PASSED: Price is currently retesting the zone.");
|
|
|
|
// --- ด่านที่ 4 (สุดท้าย): ตรวจสอบแท่งเทียนยืนยันอย่างง่าย ---
|
|
bool candle_confirmed = false;
|
|
if((zone.direction == DIRECTION_BULLISH && last_bar.close > last_bar.open) || (zone.direction == DIRECTION_BEARISH && last_bar.close < last_bar.open)) {
|
|
candle_confirmed = true;
|
|
}
|
|
|
|
if(!candle_confirmed) {
|
|
Print(" - REJECTED: Retest candle was the wrong color.");
|
|
continue;
|
|
}
|
|
Print(" - PASSED: Retest candle has correct confirmation color.");
|
|
|
|
// --- ถ้าผ่านทุกด่าน ---
|
|
Print(">>> SUCCESS! Fresh FVG Retest Signal Found. <<<");
|
|
zone.trigger_level_time = zone.time;
|
|
return zone;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
// --- Strategy 1: Retest Entry (Final version with full context awareness) ---
|
|
CSignalZone* CheckForRetestSignal(CDataContext &context)
|
|
{
|
|
// ดึงข้อมูลที่จำเป็นมาเตรียมไว้
|
|
CArrayObj* zone_list = m_zone_manager_ptr.GetZoneList();
|
|
if(zone_list == NULL) return NULL;
|
|
|
|
ENUM_MARKET_STRUCTURE_STATE structure_state = m_analyzer_ptr.GetMarketStructureState();
|
|
|
|
for(int i = 0; i < zone_list.Total(); i++)
|
|
{
|
|
CSignalZone* zone = zone_list.At(i);
|
|
|
|
// --- 1. ด่านกรองเบื้องต้น ---
|
|
if(zone == NULL || zone.state == STATE_INVALIDATED) continue;
|
|
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(zone.time);
|
|
if(level_info != NULL && level_info.trade_count >= m_max_trades_per_zone) continue;
|
|
|
|
// --- 2. แยกการพิจารณาสำหรับ BUY และ SELL ---
|
|
|
|
// --- ส่วน A: ตรวจสอบสัญญาณ BUY ที่โซน Demand ---
|
|
if (zone.direction == DIRECTION_BULLISH)
|
|
{
|
|
// 2.1 ตรวจสอบว่า "เรื่องราว" ของตลาดเอื้ออำนวยให้ Buy หรือไม่
|
|
bool is_valid_buy_narrative = false;
|
|
// เรื่องราวที่ 1: เทรดตามเทรนด์ขาขึ้น
|
|
if (m_use_continuation_retest && structure_state == MS_BULLISH) {
|
|
is_valid_buy_narrative = true;
|
|
}
|
|
// เรื่องราวที่ 2: เทรดจังหวะกลับตัวเป็นขาขึ้น
|
|
if (m_use_reversal_retest && structure_state == MS_BULLISH_CHoCH) {
|
|
is_valid_buy_narrative = true;
|
|
}
|
|
|
|
// 2.2 ถ้าเรื่องราวถูกต้อง ค่อยมองหารูปแบบแท่งเทียน
|
|
if(is_valid_buy_narrative) {
|
|
/*if(m_use_simple_reclaim_pattern && IsSimpleReclaimPattern(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}*/
|
|
if(m_use_2_bar_confirmation && Is2BarPowerCandle(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
if(m_use_3_bar_confirmation && Is3BarReversal(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
}
|
|
}
|
|
// --- ส่วน B: ตรวจสอบสัญญาณ SELL ที่โซน Supply ---
|
|
else if (zone.direction == DIRECTION_BEARISH)
|
|
{
|
|
// 2.1 ตรวจสอบว่า "เรื่องราว" ของตลาดเอื้ออำนวยให้ Sell หรือไม่
|
|
bool is_valid_sell_narrative = false;
|
|
// เรื่องราวที่ 1: เทรดตามเทรนด์ขาลง
|
|
if (m_use_continuation_retest && structure_state == MS_BEARISH) {
|
|
is_valid_sell_narrative = true;
|
|
}
|
|
// เรื่องราวที่ 2: เทรดจังหวะกลับตัวเป็นขาลง
|
|
if (m_use_reversal_retest && structure_state == MS_BEARISH_CHoCH) {
|
|
is_valid_sell_narrative = true;
|
|
}
|
|
|
|
// 2.2 ถ้าเรื่องราวถูกต้อง ค่อยมองหารูปแบบแท่งเทียน
|
|
if(is_valid_sell_narrative) {
|
|
/*if(m_use_simple_reclaim_pattern && IsSimpleReclaimPattern(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}*/
|
|
if(m_use_2_bar_confirmation && Is2BarPowerCandle(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
if(m_use_3_bar_confirmation && Is3BarReversal(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CSignalZone* CheckForBreakoutSignal(CDataContext &context, long magic_number)
|
|
{
|
|
ENUM_MARKET_STRUCTURE_STATE structure_state = m_analyzer_ptr.GetMarketStructureState();
|
|
CArrayObj* major_swings = m_zone_manager_ptr.GetMajorSwings();
|
|
if(major_swings == NULL || major_swings.Total() == 0) return NULL;
|
|
|
|
// --- Bullish Breakout ---
|
|
if(structure_state == MS_BULLISH) {
|
|
SwingPoint* last_major_high = NULL;
|
|
for(int i = major_swings.Total() - 1; i >= 0; i--) {
|
|
SwingPoint* s = major_swings.At(i);
|
|
if(s != NULL && s.type == SWING_HIGH) {
|
|
last_major_high = s;
|
|
break;
|
|
}
|
|
}
|
|
if(last_major_high != NULL) {
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(last_major_high.time);
|
|
if(level_info == NULL || level_info.trade_count < m_max_trades_per_zone) {
|
|
if(context.rates[1].close > last_major_high.price && context.rates[1].close > context.rates[1].open)
|
|
{
|
|
// --- ส่วนที่เพิ่มเข้ามา ---
|
|
PrintFormat("BREAKOUT CONFIRMED. Creating new BULLISH BREAKOUT-RETEST ZONE at %.5f", last_major_high.price);
|
|
CSignalZone* breakout_retest_zone = new CSignalZone(magic_number);
|
|
breakout_retest_zone.time = last_major_high.time;
|
|
breakout_retest_zone.top = last_major_high.price;
|
|
breakout_retest_zone.bottom = last_major_high.price - (context.atr_buffer[1] * 0.2);
|
|
breakout_retest_zone.zone_type = ZONE_BREAKOUT_RETEST; // *** SET NEW TYPE ***
|
|
breakout_retest_zone.direction = DIRECTION_BULLISH;
|
|
breakout_retest_zone.origin_swing_ptr = last_major_high;
|
|
m_zone_manager_ptr.AddZone(breakout_retest_zone);
|
|
PrintFormat("BREAKOUT CONFIRMED. Creating new BEARISH FLIP ZONE at %.5f", last_major_high.price);
|
|
// --- จบส่วนที่เพิ่ม ---
|
|
|
|
// สร้างสัญญาณสำหรับเข้าเทรดไม้แรก
|
|
if(!m_use_breakout_entry) return NULL;
|
|
CSignalZone* breakout_signal = new CSignalZone(magic_number);
|
|
breakout_signal.direction = DIRECTION_BULLISH;
|
|
breakout_signal.trigger_level_time = last_major_high.time;
|
|
breakout_signal.top = context.rates[1].high;
|
|
breakout_signal.bottom = context.rates[1].low;
|
|
return breakout_signal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// --- Bearish Breakout ---
|
|
else if(structure_state == MS_BEARISH) {
|
|
SwingPoint* last_major_low = NULL;
|
|
for(int i = major_swings.Total() - 1; i >= 0; i--) {
|
|
SwingPoint* s = major_swings.At(i);
|
|
if(s != NULL && s.type == SWING_LOW) {
|
|
last_major_low = s;
|
|
break;
|
|
}
|
|
}
|
|
if(last_major_low != NULL) {
|
|
if(context.rates[1].close < last_major_low.price && context.rates[1].close < context.rates[1].open && context.rates[1].high > last_major_low.price)
|
|
{
|
|
// --- ส่วนที่เพิ่มเข้ามา ---
|
|
PrintFormat("BREAKOUT CONFIRMED. Creating new BEARISH BREAKOUT-RETEST ZONE at %.5f", last_major_low.price);
|
|
CSignalZone* breakout_retest_zone = new CSignalZone(magic_number);
|
|
breakout_retest_zone.time = last_major_low.time;
|
|
breakout_retest_zone.bottom = last_major_low.price;
|
|
breakout_retest_zone.top = last_major_low.price + (context.atr_buffer[1] * 0.2);
|
|
breakout_retest_zone.zone_type = ZONE_BREAKOUT_RETEST; // *** SET NEW TYPE ***
|
|
breakout_retest_zone.direction = DIRECTION_BEARISH;
|
|
breakout_retest_zone.origin_swing_ptr = last_major_low;
|
|
m_zone_manager_ptr.AddZone(breakout_retest_zone);
|
|
PrintFormat("BREAKOUT CONFIRMED. Creating new BEARISH FLIP ZONE at %.5f", last_major_low.price);
|
|
// --- จบส่วนที่เพิ่ม ---
|
|
|
|
// สร้างสัญญาณสำหรับเข้าเทรดไม้แรก
|
|
if(!m_use_breakout_entry) return NULL;
|
|
CSignalZone* breakout_signal = new CSignalZone(magic_number);
|
|
breakout_signal.direction = DIRECTION_BEARISH;
|
|
breakout_signal.trigger_level_time = last_major_low.time;
|
|
breakout_signal.top = context.rates[1].high;
|
|
breakout_signal.bottom = context.rates[1].low;
|
|
return breakout_signal;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// --- Strategy: Scale-In on Breakout-Retest Zone (UPGRADED) ---
|
|
CSignalZone* CheckForRetestAfterBreakout(CDataContext &context)
|
|
{
|
|
CArrayObj* zone_list = m_zone_manager_ptr.GetZoneList();
|
|
if(zone_list == NULL) return NULL;
|
|
|
|
for(int i = 0; i < zone_list.Total(); i++)
|
|
{
|
|
CSignalZone* zone = zone_list.At(i);
|
|
|
|
// --- ด่านกรองเบื้องต้น ---
|
|
if(zone == NULL || zone.zone_type != ZONE_BREAKOUT_RETEST || zone.state == STATE_INVALIDATED) {
|
|
continue;
|
|
}
|
|
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(zone.time);
|
|
if(level_info != NULL && level_info.trade_count >= m_max_trades_per_zone) {
|
|
continue;
|
|
}
|
|
|
|
// --- ถ้าผ่านทุกด่าน ให้มองหารูปแบบแท่งเทียนยืนยัน ---
|
|
if(m_use_simple_reclaim_pattern && IsSimpleReclaimPattern(context, zone)) {
|
|
if(m_breakout_retest_number > 0 && zone.mitigation_count != (m_breakout_retest_number - 1)) {
|
|
continue;
|
|
}
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
if(m_use_2_bar_confirmation && Is2BarPowerCandle(context, zone)) {
|
|
if(m_breakout_retest_number > 0 && zone.mitigation_count != (m_breakout_retest_number - 1)) {
|
|
continue;
|
|
}
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
if(m_use_3_bar_confirmation && Is3BarReversal(context, zone)) {
|
|
if(m_breakout_retest_number > 0 && zone.mitigation_count != (m_breakout_retest_number - 1)) {
|
|
continue;
|
|
}
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// --- Strategy: Fakeout / Major Swing Failure Pattern Entry (UPGRADED with Structure Confluence) ---
|
|
CSignalZone* CheckForFakeoutSignal(CDataContext &context, long magic_number)
|
|
{
|
|
if(ArraySize(context.rates) < 4) return NULL;
|
|
|
|
CArrayObj* major_swings = m_zone_manager_ptr.GetMajorSwings();
|
|
if(major_swings == NULL || major_swings.Total() < 2) return NULL; // ต้องการ Major Swing อย่างน้อย 2 ตัวในแต่ละฝั่งเพื่อเปรียบเทียบ
|
|
|
|
// --- A. ตรวจสอบการเกิด Fakeout ที่ Major Swing High (เพื่อหาจังหวะ SELL) ---
|
|
SwingPoint* H1 = NULL; // Major High ล่าสุด
|
|
SwingPoint* H2 = NULL; // Major High ก่อนหน้า
|
|
int highs_found = 0;
|
|
for(int i = major_swings.Total() - 1; i >= 0; i--) {
|
|
SwingPoint* s = major_swings.At(i);
|
|
if(s != NULL && s.type == SWING_HIGH) {
|
|
if(highs_found == 0) H1 = s;
|
|
else if(highs_found == 1) H2 = s;
|
|
highs_found++;
|
|
if(highs_found >= 2) break;
|
|
}
|
|
}
|
|
// --- B. ตรวจสอบการเกิด Fakeout ที่ Major Swing Low (เพื่อหาจังหวะ BUY) ---
|
|
SwingPoint* L1 = NULL; // Major Low ล่าสุด
|
|
SwingPoint* L2 = NULL; // Major Low ก่อนหน้า
|
|
int lows_found = 0;
|
|
for(int i = major_swings.Total() - 1; i >= 0; i--) {
|
|
SwingPoint* s = major_swings.At(i);
|
|
if(s != NULL && s.type == SWING_LOW) {
|
|
if(lows_found == 0) L1 = s;
|
|
else if(lows_found == 1) L2 = s;
|
|
lows_found++;
|
|
if(lows_found >= 2) break;
|
|
}
|
|
}
|
|
|
|
if(H1 != NULL && H2 != NULL && L1 != NULL && L2 != NULL) {
|
|
// +++ NEW: Market Structure Confirmation Filter +++
|
|
// ต้องเป็นโครงสร้างขาลง (Lower Highs) เท่านั้น
|
|
if(H1.price < H2.price && L1.price < L2.price)
|
|
{
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(H1.time);
|
|
if(level_info == NULL || level_info.trade_count < m_max_trades_per_zone) {
|
|
bool is_fakeout_candle = (context.rates[1].high > H1.price && context.rates[1].close < H1.price);
|
|
if(is_fakeout_candle) {
|
|
PrintFormat("--- FAKEOUT SETUP ARMED: Bearish Fakeout of Major High at %s. Checking for confirmation...", TimeToString(H1.time));
|
|
|
|
// 3. ถ้าใช่ ให้สร้าง "โซนเสมือน" ขึ้นมาเพื่อใช้ตรวจสอบรูปแบบการกลับตัว
|
|
CSignalZone* virtual_zone = new CSignalZone(magic_number);
|
|
virtual_zone.direction = DIRECTION_BEARISH;
|
|
virtual_zone.top = context.rates[2].high +2 ;
|
|
virtual_zone.bottom = context.rates[2].low -2 ;
|
|
|
|
// 4. ใช้รูปแบบ 3-Bar Reversal ที่แข็งแกร่งเป็นตัวยืนยันสุดท้าย
|
|
if(m_use_3_bar_confirmation && Is3BarReversal(context, virtual_zone)) {
|
|
Print(">>> FAKEOUT SIGNAL: Bearish Fakeout confirmed! Creating SELL signal.");
|
|
virtual_zone.trigger_level_time = H1.time;
|
|
return virtual_zone; // ส่งสัญญาณเทรด
|
|
}
|
|
if(m_use_2_bar_confirmation && Is2BarPowerCandle(context, virtual_zone)) {
|
|
virtual_zone.trigger_level_time = H1.time;
|
|
return virtual_zone;
|
|
}
|
|
/*if(m_use_simple_reclaim_pattern && IsSimpleReclaimPattern(context, virtual_zone)) {
|
|
virtual_zone.trigger_level_time = H1.time;
|
|
return virtual_zone;
|
|
} */
|
|
delete virtual_zone; // ถ้าไม่เข้าเงื่อนไข ให้ลบทิ้ง
|
|
}
|
|
}
|
|
}
|
|
|
|
// +++ NEW: Market Structure Confirmation Filter +++
|
|
// ต้องเป็นโครงสร้างขาขึ้น (Higher Lows) เท่านั้น
|
|
if(L1.price > L2.price && H1.price > H2.price)
|
|
{
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(L1.time);
|
|
if(level_info == NULL || level_info.trade_count < m_max_trades_per_zone) {
|
|
bool is_fakeout_candle = (context.rates[1].low < L1.price && context.rates[1].close > L1.price);
|
|
if(is_fakeout_candle) {
|
|
PrintFormat("--- FAKEOUT SETUP ARMED: Bullish Fakeout of Major Low at %s. Checking for confirmation...", TimeToString(L1.time));
|
|
CSignalZone* virtual_zone = new CSignalZone(magic_number);
|
|
virtual_zone.direction = DIRECTION_BULLISH;
|
|
virtual_zone.top = context.rates[2].high + 2;
|
|
virtual_zone.bottom = context.rates[2].low -2 ;
|
|
|
|
if(m_use_3_bar_confirmation && Is3BarReversal(context, virtual_zone)) {
|
|
Print(">>> FAKEOUT SIGNAL: Bullish Fakeout confirmed! Creating BUY signal.");
|
|
virtual_zone.trigger_level_time = L1.time;
|
|
return virtual_zone;
|
|
}
|
|
if(m_use_2_bar_confirmation && Is2BarPowerCandle(context, virtual_zone)) {
|
|
virtual_zone.trigger_level_time = L1.time;
|
|
return virtual_zone;
|
|
}
|
|
/*if(m_use_simple_reclaim_pattern && IsSimpleReclaimPattern(context, virtual_zone)) {
|
|
virtual_zone.trigger_level_time = L1.time;
|
|
return virtual_zone;
|
|
} */
|
|
delete virtual_zone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CSignalZone* CheckForMajorSwingSignal(CDataContext &context, long magic_number)
|
|
{
|
|
CArrayObj* major_swings = m_zone_manager_ptr.GetMajorSwings();
|
|
if(major_swings == NULL || major_swings.Total() == 0) return NULL;
|
|
|
|
SwingPoint* last_major_swing = major_swings.At(major_swings.Total() - 1);
|
|
if(last_major_swing == NULL) return NULL;
|
|
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(last_major_swing.time);
|
|
if(level_info != NULL && level_info.trade_count > 0) return NULL; // เทรดได้แค่ครั้งแรกที่เจอ
|
|
|
|
CSignalZone* momentum_signal = NULL;
|
|
if(last_major_swing.type == SWING_LOW) {
|
|
momentum_signal = new CSignalZone(magic_number);
|
|
momentum_signal.direction = DIRECTION_BULLISH;
|
|
momentum_signal.trigger_level_time = last_major_swing.time;
|
|
int bar_idx = iBarShift(_Symbol, PERIOD_CURRENT, last_major_swing.time);
|
|
if(bar_idx >= 0) {
|
|
momentum_signal.bottom = iLow(_Symbol, PERIOD_CURRENT, bar_idx);
|
|
momentum_signal.top = iHigh(_Symbol, PERIOD_CURRENT, bar_idx);
|
|
}
|
|
} else if(last_major_swing.type == SWING_HIGH) {
|
|
momentum_signal = new CSignalZone(magic_number);
|
|
momentum_signal.direction = DIRECTION_BEARISH;
|
|
momentum_signal.trigger_level_time = last_major_swing.time;
|
|
int bar_idx = iBarShift(_Symbol, PERIOD_CURRENT, last_major_swing.time);
|
|
if(bar_idx >= 0) {
|
|
momentum_signal.top = iHigh(_Symbol, PERIOD_CURRENT, bar_idx);
|
|
momentum_signal.bottom = iLow(_Symbol, PERIOD_CURRENT, bar_idx);
|
|
}
|
|
}
|
|
return momentum_signal;
|
|
}
|
|
// --- Strategy: Swing Failure Pattern (SFP) Entry ---
|
|
CSignalZone* CheckForSfpSignal(CDataContext &context, long magic_number)
|
|
{
|
|
if(ArraySize(context.rates) < 3) return NULL;
|
|
CArrayObj* all_swings = m_zone_manager_ptr.GetAllSwings();
|
|
if(all_swings == NULL || all_swings.Total() == 0) return NULL;
|
|
|
|
// --- Check for Bullish SFP (to BUY) ---
|
|
// 1. แท่งยืนยัน (rates[1]) ต้องเป็นแท่งเขียว
|
|
if(context.rates[1].close > context.rates[1].open)
|
|
{
|
|
// 2. หา Swing Low ก่อนหน้าแท่งที่อาจจะเป็น SFP (rates[2])
|
|
SwingPoint* prev_low = GetPreviousSwing(2, SWING_LOW, all_swings);
|
|
if(prev_low != NULL)
|
|
{
|
|
// 3. เช็คว่าแท่งที่ 2 เป็นแท่ง SFP จริงหรือไม่ (ไส้ทะลุ, เนื้อปิดกลับ)
|
|
bool is_sfp_candle = (context.rates[2].low < prev_low.price) && (context.rates[2].close > prev_low.price);
|
|
if(is_sfp_candle)
|
|
{
|
|
// 4. เช็คบัญชีดำ
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(prev_low.time);
|
|
if(level_info == NULL || level_info.trade_count < m_max_trades_per_zone)
|
|
{
|
|
Print("--- SFP SIGNAL: Bullish SFP Detected! ---");
|
|
CSignalZone* sfp_signal = new CSignalZone(magic_number);
|
|
sfp_signal.direction = DIRECTION_BULLISH;
|
|
sfp_signal.trigger_level_time = prev_low.time;
|
|
sfp_signal.bottom = context.rates[2].low; // SL อิงจาก Low ของแท่ง SFP
|
|
sfp_signal.top = context.rates[2].high;
|
|
return sfp_signal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Check for Bearish SFP (to SELL) ---
|
|
// 1. แท่งยืนยัน (rates[1]) ต้องเป็นแท่งแดง
|
|
if(context.rates[1].close < context.rates[1].open)
|
|
{
|
|
// 2. หา Swing High ก่อนหน้าแท่ง SFP
|
|
SwingPoint* prev_high = GetPreviousSwing(2, SWING_HIGH, all_swings);
|
|
if(prev_high != NULL)
|
|
{
|
|
// 3. เช็คว่าแท่งที่ 2 เป็นแท่ง SFP จริงหรือไม่
|
|
bool is_sfp_candle = (context.rates[2].high > prev_high.price) && (context.rates[2].close < prev_high.price);
|
|
if(is_sfp_candle) {
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(prev_high.time);
|
|
if(level_info == NULL || level_info.trade_count < m_max_trades_per_zone)
|
|
{
|
|
Print("--- SFP SIGNAL: Bearish SFP Detected! ---");
|
|
CSignalZone* sfp_signal = new CSignalZone(magic_number);
|
|
sfp_signal.direction = DIRECTION_BEARISH;
|
|
sfp_signal.trigger_level_time = prev_high.time;
|
|
sfp_signal.top = context.rates[2].high; // SL อิงจาก High ของแท่ง SFP
|
|
sfp_signal.bottom = context.rates[2].low;
|
|
return sfp_signal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
// --- Strategy: Liquidity Sweep into POI Entry ---
|
|
CSignalZone* CheckForSweepToPoiSignal(CDataContext &context)
|
|
{
|
|
CArrayObj* all_zones = m_zone_manager_ptr.GetZoneList();
|
|
CArrayObj* all_swings = m_zone_manager_ptr.GetAllSwings();
|
|
if(all_zones == NULL || all_swings == NULL || ArraySize(context.rates) < 2) return NULL;
|
|
|
|
// 1. วนลูปหาโซนคุณภาพสูง (POI) ที่พร้อมเทรด
|
|
for(int i = 0; i < all_zones.Total(); i++) {
|
|
CSignalZone* zone = all_zones.At(i);
|
|
if(zone == NULL || zone.state == STATE_INVALIDATED) continue;
|
|
|
|
CTradedLevel* level_info = m_zone_manager_ptr.GetTradedLevelInfo(zone.time);
|
|
if(level_info != NULL && level_info.trade_count >= m_max_trades_per_zone) continue;
|
|
|
|
// 2. สำหรับแต่ละโซน, หา Liquidity ที่อยู่ใกล้ๆ (Swing ก่อนหน้า)
|
|
SwingPoint* liquidity_swing = NULL;
|
|
int zone_bar_idx = iBarShift(_Symbol, PERIOD_CURRENT, zone.time);
|
|
if(zone.direction == DIRECTION_BULLISH) { // โซน Demand
|
|
liquidity_swing = GetPreviousSwing(zone_bar_idx, SWING_LOW, all_swings);
|
|
} else { // โซน Supply
|
|
liquidity_swing = GetPreviousSwing(zone_bar_idx, SWING_HIGH, all_swings);
|
|
}
|
|
|
|
// 3. ตรวจสอบว่ามี Liquidity ให้กวาดและอยู่ในตำแหน่งที่ถูกต้องหรือไม่
|
|
if(liquidity_swing != NULL) {
|
|
bool is_valid_setup = (zone.direction == DIRECTION_BULLISH && liquidity_swing.price > zone.top) ||
|
|
(zone.direction == DIRECTION_BEARISH && liquidity_swing.price < zone.bottom);
|
|
|
|
if(is_valid_setup) {
|
|
// 4. ตรวจสอบแท่งเทียนล่าสุด (rates[1]) ว่าเกิดเหตุการณ์ "กวาดแล้วแตะ" หรือไม่
|
|
MqlRates last_bar = context.rates[1];
|
|
bool swept_and_tapped = false;
|
|
|
|
if(zone.direction == DIRECTION_BULLISH && last_bar.low < liquidity_swing.price && last_bar.low <= zone.top) {
|
|
swept_and_tapped = true;
|
|
} else if(zone.direction == DIRECTION_BEARISH && last_bar.high > liquidity_swing.price && last_bar.high >= zone.bottom) {
|
|
swept_and_tapped = true;
|
|
}
|
|
|
|
// 5. ถ้าใช่, ให้มองหารูปแบบแท่งเทียนยืนยันเพื่อเข้าเทรด
|
|
if(swept_and_tapped) {
|
|
PrintFormat("--- SWEEP+POI SETUP ARMED at zone %s, checking for confirmation...", TimeToString(zone.time));
|
|
if(m_use_simple_reclaim_pattern && IsSimpleReclaimPattern(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
|
|
if(m_use_2_bar_confirmation && Is2BarPowerCandle(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
if(m_use_3_bar_confirmation && Is3BarReversal(context, zone)) {
|
|
zone.trigger_level_time = zone.time; return zone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
public:
|
|
CEntryExecutor(CZoneManager* zone_manager, CStructureAnalyzer* analyzer, int max_trades,
|
|
bool use_continuation, bool use_reversal, bool use_breakout, bool use_fakeout,
|
|
bool use_major_swing, bool use_sfp, bool use_sweep_poi,
|
|
bool use_scale_in, int retest_num, bool use_fresh_fvg,
|
|
bool use_simple, bool use_2_bar, bool use_3_bar,
|
|
bool use_sto_confirm, int sto_ob, int sto_os,
|
|
ENUM_RETEST_CONFIRMATION_MODE retest_mode, double retest_atr_mult)
|
|
{
|
|
m_zone_manager_ptr = zone_manager;
|
|
m_analyzer_ptr = analyzer;
|
|
m_max_trades_per_zone = max_trades;
|
|
m_use_continuation_retest = use_continuation;
|
|
m_use_reversal_retest = use_reversal;
|
|
m_use_breakout_entry = use_breakout;
|
|
m_use_fakeout_entry = use_fakeout;
|
|
m_use_major_swing_momentum_entry = use_major_swing;
|
|
m_use_sfp_entry = use_sfp;
|
|
m_use_sweep_and_poi_entry = use_sweep_poi;
|
|
m_use_scale_in_on_breakout = use_scale_in;
|
|
m_breakout_retest_number = retest_num;
|
|
m_use_fresh_fvg_retest_entry = use_fresh_fvg;
|
|
m_use_simple_reclaim_pattern = use_simple;
|
|
m_use_2_bar_confirmation = use_2_bar;
|
|
m_use_3_bar_confirmation = use_3_bar;
|
|
m_use_sto_for_entry_confirmation = use_sto_confirm;
|
|
m_sto_overbought = sto_ob;
|
|
m_sto_oversold = sto_os;
|
|
m_retest_confirmation_mode = retest_mode;
|
|
m_retest_min_atr_moveaway = retest_atr_mult;
|
|
}
|
|
~CEntryExecutor() {}
|
|
|
|
// --- The New, Unified Master "Brain" ---
|
|
CSignalZone* FindTradeSignal(CDataContext &context, long magic_number)
|
|
{
|
|
CSignalZone* signal = NULL;
|
|
// ไล่ตรวจสอบแต่ละท่าเทรดตามลำดับความสำคัญหรือความถี่ที่ต้องการ
|
|
if(m_use_fresh_fvg_retest_entry) { signal = CheckForFreshFvgRetest(context); if(signal != NULL) return signal; }
|
|
if(m_use_continuation_retest || m_use_reversal_retest) { signal = CheckForRetestSignal(context); if(signal != NULL) return signal; }
|
|
if(m_use_sweep_and_poi_entry) { signal = CheckForSweepToPoiSignal(context); if(signal != NULL) return signal; }
|
|
if(m_use_breakout_entry || m_use_scale_in_on_breakout) { signal = CheckForBreakoutSignal(context, magic_number); if(signal != NULL) return signal; }
|
|
if(m_use_scale_in_on_breakout) { signal = CheckForRetestAfterBreakout(context); if(signal != NULL) return signal; }
|
|
if(m_use_fakeout_entry) { signal = CheckForFakeoutSignal(context, magic_number); if(signal != NULL) return signal; }
|
|
if(m_use_sfp_entry) { signal = CheckForSfpSignal(context, magic_number); if(signal != NULL) return signal; }
|
|
if(m_use_major_swing_momentum_entry) { signal = CheckForMajorSwingSignal(context, magic_number); if(signal != NULL) return signal; }
|
|
|
|
return NULL;
|
|
}
|
|
|
|
};
|
|
#endif |