2727 lines
No EOL
121 KiB
MQL5
2727 lines
No EOL
121 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Daily Sweep + M15 Turtlesoup.mq5|
|
|
//| Copyright 2025, Setup Radar |
|
|
//| https://www.Setup-Radar.com |
|
|
//| Author: X.com/Hectorand |
|
|
//|Production Ready Code |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Setup Radar"
|
|
#property link "https://www.Setup-Radar.com"
|
|
#property version "1.5" // Updated version with trade execution
|
|
|
|
// Include sector mapping
|
|
#include <SymbolToSectorLink.mqh>
|
|
#include <Trade/Trade.mqh>
|
|
|
|
// ============================================================
|
|
// INPUT PARAMETERS
|
|
// ============================================================
|
|
input int SwingLeftBars = 2; // Number of bars to check on the left for swing points
|
|
input int SwingRightBars = 2; // Number of bars to check on the right for swing points
|
|
input bool EnableDebugPrints = false; // Enable debug prints for screenshot and API calls
|
|
input int MinCandlesForTradeableDay = 48; // Minimum M15 candles for a day to be considered "tradeable"
|
|
input bool CloseChartAfterScreenshot = true; // Close temporary chart after screenshot
|
|
input double LotSize = 0.01; // Lot size for trades
|
|
input double MaxRiskPercent = 2.0; // Maximum risk as percentage of account balance
|
|
input bool EnableAutoTrading = true; // Enable automatic trade execution
|
|
|
|
string strategyName = "Daily Sweep + M15 Turtlesoup"; // Strategy identifier for alerts
|
|
string strategyId = "0000001";
|
|
string allowedTimeframe[]; // Empty array, no elements
|
|
|
|
// ============================================================
|
|
// CONFIGURATION CONSTANTS
|
|
// ============================================================
|
|
int SwingLookbackBars = 20; // Number of bars to look back for swing detection
|
|
|
|
// Server URLs for alert and screenshot delivery
|
|
string alertServerURL = "https://api.setupradar.app/api/v1/strategy/webhook"; // Endpoint for alert JSON data
|
|
string screenshotServerURL = "https://api.setupradar.app/api/v1/strategy/webhook"; // Endpoint for screenshot binary data
|
|
|
|
// Trading session definitions
|
|
string SydneySessionStart = "22:00"; // Sydney session start time (crosses midnight)
|
|
string SydneySessionEnd = "00:00"; // Sydney session end time
|
|
string AsiaSessionStart = "00:00"; // Asian session start time
|
|
string AsiaSessionEnd = "07:00"; // Asian session end time
|
|
string LondonSessionStart = "07:00"; // London session start time
|
|
string LondonSessionEnd = "12:00"; // London session end time
|
|
string NewYorkSessionStart = "12:00"; // New York session start time
|
|
string NewYorkSessionEnd = "22:00"; // New York session end time
|
|
|
|
// ============================================================
|
|
// TIME TRACKING VARIABLES
|
|
// ============================================================
|
|
string currentSession = "OutsideSession"; // Current trading session name
|
|
|
|
// ============================================================
|
|
// MARKET BIAS ENUMERATION AND STATE
|
|
// ============================================================
|
|
enum ENUM_BIAS
|
|
{
|
|
BIAS_NEUTRAL,
|
|
BIAS_BULLISH,
|
|
BIAS_BEARISH
|
|
};
|
|
|
|
// ============================================================
|
|
// TRADE STATE ENUMERATION
|
|
// ============================================================
|
|
enum ENUM_TRADE_STATE
|
|
{
|
|
TRADE_NONE, // No trade placed
|
|
TRADE_PENDING, // Alert triggered, waiting for retracement
|
|
TRADE_EXECUTED // Trade has been executed
|
|
};
|
|
|
|
// ============================================================
|
|
// SYMBOL-SPECIFIC DATA STRUCTURES
|
|
// ============================================================
|
|
|
|
// Market bias per symbol
|
|
struct BiasData
|
|
{
|
|
string symbol;
|
|
ENUM_BIAS bias;
|
|
};
|
|
|
|
// Retracement tracking per symbol (NEW - separate from main alerts)
|
|
struct RetracementTracker
|
|
{
|
|
string symbol; // Symbol name
|
|
|
|
// Bullish retracement data
|
|
bool bullishBreakoutOccurred; // Flag if bullish breakout happened
|
|
datetime bullishBreakoutTime; // Time of bullish breakout
|
|
double bullishBreakoutPrice; // Price at breakout (A point)
|
|
double bullishBPrice; // B point price
|
|
double bullishSwingHigh; // Swing high price
|
|
datetime bullishSwingHighTime; // Swing high time
|
|
double bullishFortyPercentLevel; // 40% level for retracement
|
|
double bullishLast_LL_Prices[2]; // Last two lower low prices
|
|
datetime bullishLast_LL_Times[2]; // Last two lower low times
|
|
double bullishLast_HH_Prices[2]; // Last two higher high prices (for reference)
|
|
datetime bullishLast_HH_Times[2]; // Last two higher high times (for reference)
|
|
double bullishPrevDayLow; // Previous day low
|
|
datetime bullishPrevDayLowTime; // Previous day low time
|
|
ENUM_TRADE_STATE bullishTradeState; // Track trade state for bullish
|
|
ulong bullishTradeTicket; // Ticket of executed trade
|
|
|
|
// Bearish retracement data
|
|
bool bearishBreakoutOccurred; // Flag if bearish breakout happened
|
|
datetime bearishBreakoutTime; // Time of bearish breakout
|
|
double bearishBreakoutPrice; // Price at breakout (A point)
|
|
double bearishBPrice; // B point price
|
|
double bearishSwingLow; // Swing low price
|
|
datetime bearishSwingLowTime; // Swing low time
|
|
double bearishFortyPercentLevel; // 40% level for retracement
|
|
double bearishLast_HH_Prices[2]; // Last two higher high prices
|
|
datetime bearishLast_HH_Times[2]; // Last two higher high times
|
|
double bearishLast_LL_Prices[2]; // Last two lower low prices (for reference)
|
|
datetime bearishLast_LL_Times[2]; // Last two lower low times (for reference)
|
|
double bearishPrevDayHigh; // Previous day high
|
|
datetime bearishPrevDayHighTime; // Previous day high time
|
|
ENUM_TRADE_STATE bearishTradeState; // Track trade state for bearish
|
|
ulong bearishTradeTicket; // Ticket of executed trade
|
|
};
|
|
|
|
// Alert tracking per symbol (ORIGINAL - UNCHANGED)
|
|
struct AlertTracker
|
|
{
|
|
string symbol; // Symbol name
|
|
bool bullishAlertSent; // Bullish alert sent flag for this symbol
|
|
int bullishAlertCount; // Bullish alert count for this symbol
|
|
bool bearishAlertSent; // Bearish alert sent flag for this symbol
|
|
int bearishAlertCount; // Bearish alert count for this symbol
|
|
double lastBullishSwingHigh; // Last alerted bullish swing high for this symbol
|
|
double lastBearishSwingLow; // Last alerted bearish swing low for this symbol
|
|
datetime bullishAlertTime; // Time when bullish alert was sent (C time - FIXED)
|
|
datetime bearishAlertTime; // Time when bearish alert was sent (C time - FIXED)
|
|
};
|
|
|
|
// Previous day data per symbol
|
|
struct PrevDayData
|
|
{
|
|
string symbol;
|
|
datetime lowTime; // Time of previous day's low (M15 candle)
|
|
int lowIndex; // Bar index of previous day's low
|
|
double lowPrice; // Price of previous day's low
|
|
datetime highTime; // Time of previous day's high (M15 candle)
|
|
int highIndex; // Bar index of previous day's high
|
|
double highPrice; // Price of previous day's high
|
|
};
|
|
|
|
// Swing point data per symbol
|
|
struct SwingData
|
|
{
|
|
string symbol;
|
|
|
|
// Dynamic arrays for storing all detected swing points
|
|
double swingLowPrices[];
|
|
datetime swingLowTimes[];
|
|
double swingHighPrices[];
|
|
datetime swingHighTimes[];
|
|
|
|
// Arrays for last 2 consecutive higher highs (temporary)
|
|
double HH_Prices[2]; // [0] = H1 (older), [1] = H2 (newer)
|
|
datetime HH_Times[2]; // [0] = H1 time, [1] = H2 time
|
|
|
|
// Arrays for last 2 consecutive lower lows (temporary)
|
|
double LL_Prices[2]; // [0] = L1 (older), [1] = L2 (newer)
|
|
datetime LL_Times[2]; // [0] = L1 time, [1] = L2 time
|
|
|
|
// Static arrays for valid last 2 consecutive swings (persistent)
|
|
double Last_HH_Prices[2]; // [0] = H1 (older), [1] = H2 (newer) - static
|
|
datetime Last_HH_Times[2]; // [0] = H1 time, [1] = H2 time - static
|
|
double Last_LL_Prices[2]; // [0] = L1 (older), [1] = L2 (newer) - static
|
|
datetime Last_LL_Times[2]; // [0] = L1 time, [1] = L2 time - static
|
|
|
|
// Bullish trading scenario variables
|
|
double bullishSwingHigh; // Current bullish swing high (resistance level) - Point A
|
|
datetime bullishSwingHighTime; // Time when bullish swing high occurred
|
|
int bullishBarsInBetween; // Number of bars between two bullish swing lows
|
|
|
|
// Bearish trading scenario variables
|
|
double bearishSwingLow; // Current bearish swing low (support level) - Point A
|
|
datetime bearishSwingLowTime; // Time when bearish swing low occurred
|
|
int bearishBarsInBetween; // Number of bars between two bearish swing highs
|
|
|
|
// Current market prices
|
|
double currentAskPrice;
|
|
double currentBidPrice;
|
|
|
|
// Pattern validity flags
|
|
bool bullishPatternValid; // Flag indicating if bullish pattern is valid based on PDL condition
|
|
bool bearishPatternValid; // Flag indicating if bearish pattern is valid based on PDH condition
|
|
|
|
// Enhanced validation flags
|
|
bool bullishBIsLowest; // Flag: B is the lowest low between SSL and C
|
|
bool bullishAIsHighest; // Flag: A is the highest high between A and C+1
|
|
bool bearishBIsHighest; // Flag: B is the highest high between BSL and C
|
|
bool bearishAIsLowest; // Flag: A is the lowest low between A and C+1
|
|
};
|
|
|
|
// ============================================================
|
|
// GLOBAL ARRAYS (Symbol-Specific)
|
|
// ============================================================
|
|
string Symbols[];
|
|
int SymbolsCount;
|
|
datetime last_bar_time[];
|
|
datetime last_bar_time_d[];
|
|
|
|
BiasData biasData[];
|
|
AlertTracker alertTrackers[]; // ORIGINAL - UNCHANGED
|
|
RetracementTracker retraceTrackers[]; // NEW - separate tracking
|
|
PrevDayData prevDayData[];
|
|
SwingData swingData[];
|
|
|
|
CTrade trade; // Global trade object
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
ArrayResize(allowedTimeframe, 1);
|
|
allowedTimeframe[0] = "M15";
|
|
|
|
// Initialize trade object
|
|
trade.SetExpertMagicNumber(12345);
|
|
trade.SetDeviationInPoints(10);
|
|
|
|
// Get all symbols
|
|
SymbolsCount = SymbolsTotal(true);
|
|
ArrayResize(Symbols, SymbolsCount);
|
|
ArrayResize(last_bar_time, SymbolsCount);
|
|
ArrayResize(last_bar_time_d, SymbolsCount);
|
|
|
|
// Initialize symbol-specific data arrays
|
|
ArrayResize(biasData, SymbolsCount);
|
|
ArrayResize(alertTrackers, SymbolsCount); // ORIGINAL
|
|
ArrayResize(retraceTrackers, SymbolsCount); // NEW
|
|
ArrayResize(prevDayData, SymbolsCount);
|
|
ArrayResize(swingData, SymbolsCount);
|
|
|
|
for(int i = 0; i < SymbolsCount; i++)
|
|
{
|
|
string symbol = SymbolName(i, true);
|
|
Symbols[i] = symbol;
|
|
|
|
// Initialize time tracking
|
|
last_bar_time[i] = iTime(symbol, PERIOD_M15, 0);
|
|
last_bar_time_d[i] = iTime(symbol, PERIOD_D1, 0);
|
|
|
|
// Initialize bias data
|
|
biasData[i].symbol = symbol;
|
|
biasData[i].bias = BIAS_NEUTRAL;
|
|
|
|
// Initialize alert trackers (ORIGINAL - UNCHANGED)
|
|
alertTrackers[i].symbol = symbol;
|
|
alertTrackers[i].bullishAlertSent = false;
|
|
alertTrackers[i].bullishAlertCount = 0;
|
|
alertTrackers[i].bearishAlertSent = false;
|
|
alertTrackers[i].bearishAlertCount = 0;
|
|
alertTrackers[i].lastBullishSwingHigh = 0;
|
|
alertTrackers[i].lastBearishSwingLow = 0;
|
|
alertTrackers[i].bullishAlertTime = 0;
|
|
alertTrackers[i].bearishAlertTime = 0;
|
|
|
|
// Initialize retracement trackers (NEW)
|
|
retraceTrackers[i].symbol = symbol;
|
|
retraceTrackers[i].bullishBreakoutOccurred = false;
|
|
retraceTrackers[i].bullishBreakoutTime = 0;
|
|
retraceTrackers[i].bullishBreakoutPrice = 0;
|
|
retraceTrackers[i].bullishBPrice = 0;
|
|
retraceTrackers[i].bullishSwingHigh = 0;
|
|
retraceTrackers[i].bullishSwingHighTime = 0;
|
|
retraceTrackers[i].bullishFortyPercentLevel = 0;
|
|
retraceTrackers[i].bullishTradeState = TRADE_NONE;
|
|
retraceTrackers[i].bullishTradeTicket = 0;
|
|
ArrayInitialize(retraceTrackers[i].bullishLast_LL_Prices, 0);
|
|
ArrayInitialize(retraceTrackers[i].bullishLast_LL_Times, 0);
|
|
ArrayInitialize(retraceTrackers[i].bullishLast_HH_Prices, 0);
|
|
ArrayInitialize(retraceTrackers[i].bullishLast_HH_Times, 0);
|
|
retraceTrackers[i].bullishPrevDayLow = 0;
|
|
retraceTrackers[i].bullishPrevDayLowTime = 0;
|
|
|
|
retraceTrackers[i].bearishBreakoutOccurred = false;
|
|
retraceTrackers[i].bearishBreakoutTime = 0;
|
|
retraceTrackers[i].bearishBreakoutPrice = 0;
|
|
retraceTrackers[i].bearishBPrice = 0;
|
|
retraceTrackers[i].bearishSwingLow = 0;
|
|
retraceTrackers[i].bearishSwingLowTime = 0;
|
|
retraceTrackers[i].bearishFortyPercentLevel = 0;
|
|
retraceTrackers[i].bearishTradeState = TRADE_NONE;
|
|
retraceTrackers[i].bearishTradeTicket = 0;
|
|
ArrayInitialize(retraceTrackers[i].bearishLast_HH_Prices, 0);
|
|
ArrayInitialize(retraceTrackers[i].bearishLast_HH_Times, 0);
|
|
ArrayInitialize(retraceTrackers[i].bearishLast_LL_Prices, 0);
|
|
ArrayInitialize(retraceTrackers[i].bearishLast_LL_Times, 0);
|
|
retraceTrackers[i].bearishPrevDayHigh = 0;
|
|
retraceTrackers[i].bearishPrevDayHighTime = 0;
|
|
|
|
// Initialize previous day data
|
|
prevDayData[i].symbol = symbol;
|
|
prevDayData[i].lowTime = 0;
|
|
prevDayData[i].lowIndex = -1;
|
|
prevDayData[i].lowPrice = 0;
|
|
prevDayData[i].highTime = 0;
|
|
prevDayData[i].highIndex = -1;
|
|
prevDayData[i].highPrice = 0;
|
|
|
|
// Initialize swing data arrays
|
|
swingData[i].symbol = symbol;
|
|
ArrayResize(swingData[i].swingLowPrices, 0);
|
|
ArrayResize(swingData[i].swingLowTimes, 0);
|
|
ArrayResize(swingData[i].swingHighPrices, 0);
|
|
ArrayResize(swingData[i].swingHighTimes, 0);
|
|
|
|
ArrayInitialize(swingData[i].HH_Prices, EMPTY_VALUE);
|
|
ArrayInitialize(swingData[i].HH_Times, 0);
|
|
ArrayInitialize(swingData[i].LL_Prices, EMPTY_VALUE);
|
|
ArrayInitialize(swingData[i].LL_Times, 0);
|
|
|
|
ArrayInitialize(swingData[i].Last_HH_Prices, 0);
|
|
ArrayInitialize(swingData[i].Last_HH_Times, 0);
|
|
ArrayInitialize(swingData[i].Last_LL_Prices, 0);
|
|
ArrayInitialize(swingData[i].Last_LL_Times, 0);
|
|
|
|
swingData[i].bullishSwingHigh = 0;
|
|
swingData[i].bullishSwingHighTime = 0;
|
|
swingData[i].bullishBarsInBetween = 0;
|
|
swingData[i].bearishSwingLow = 0;
|
|
swingData[i].bearishSwingLowTime = 0;
|
|
swingData[i].bearishBarsInBetween = 0;
|
|
|
|
swingData[i].currentAskPrice = 0;
|
|
swingData[i].currentBidPrice = 0;
|
|
|
|
// Initialize pattern validity flags
|
|
swingData[i].bullishPatternValid = false;
|
|
swingData[i].bearishPatternValid = false;
|
|
|
|
// Initialize enhanced validation flags
|
|
swingData[i].bullishBIsLowest = false;
|
|
swingData[i].bullishAIsHighest = false;
|
|
swingData[i].bearishBIsHighest = false;
|
|
swingData[i].bearishAIsLowest = false;
|
|
}
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Expert Advisor initialized. Monitoring ", SymbolsCount, " symbols");
|
|
Print("DEBUG: Created symbol-specific data structures for all symbols");
|
|
Print("DEBUG: 2-Alert system enabled (Breakout + Retracement)");
|
|
Print("DEBUG: Auto-trading is ", EnableAutoTrading ? "ENABLED" : "DISABLED");
|
|
}
|
|
|
|
EventSetTimer(2);
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Clean up all chart objects
|
|
DeleteAllObjects();
|
|
|
|
EventKillTimer();
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Expert Advisor deinitialized. Reason: ", reason);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get symbol index in all data arrays |
|
|
//+------------------------------------------------------------------+
|
|
int GetSymbolIndex(string symbol)
|
|
{
|
|
for(int i = 0; i < SymbolsCount; i++)
|
|
{
|
|
if(Symbols[i] == symbol)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert timer function - MAIN EXECUTION LOOP |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
for(int i = 0; i < SymbolsCount; i++)
|
|
{
|
|
string symbol = Symbols[i];
|
|
|
|
// Update current market prices
|
|
swingData[i].currentAskPrice = SymbolInfoDouble(symbol, SYMBOL_ASK);
|
|
swingData[i].currentBidPrice = SymbolInfoDouble(symbol, SYMBOL_BID);
|
|
|
|
// Check if new trading day has started
|
|
if(IsNewDay(i))
|
|
{
|
|
biasData[i].bias = BIAS_NEUTRAL; // Reset bias for this symbol
|
|
|
|
// Reset alert counters for this symbol (ORIGINAL - UNCHANGED)
|
|
alertTrackers[i].bullishAlertCount = 0;
|
|
alertTrackers[i].bearishAlertCount = 0;
|
|
alertTrackers[i].bullishAlertSent = false;
|
|
alertTrackers[i].bearishAlertSent = false;
|
|
|
|
// Reset retracement trackers (NEW)
|
|
retraceTrackers[i].bullishBreakoutOccurred = false;
|
|
retraceTrackers[i].bearishBreakoutOccurred = false;
|
|
retraceTrackers[i].bullishTradeState = TRADE_NONE;
|
|
retraceTrackers[i].bearishTradeState = TRADE_NONE;
|
|
|
|
// Reset pattern validity flags
|
|
swingData[i].bullishPatternValid = false;
|
|
swingData[i].bearishPatternValid = false;
|
|
swingData[i].bullishBIsLowest = false;
|
|
swingData[i].bullishAIsHighest = false;
|
|
swingData[i].bearishBIsHighest = false;
|
|
swingData[i].bearishAIsLowest = false;
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Daily reset for ", symbol, " - Counters and retracement flags reset");
|
|
}
|
|
}
|
|
|
|
// Check for new 15-minute bar formation
|
|
if(IsNew15MinBar(i))
|
|
{
|
|
currentSession = GetCurrentSession(); // Global session (same for all)
|
|
|
|
// Calculate previous day's high and low from M15 candles for THIS symbol
|
|
prevDayData[i].lowTime = GetM15PrevDayLowTime(symbol);
|
|
if(prevDayData[i].lowTime > 0)
|
|
{
|
|
prevDayData[i].lowIndex = iBarShift(symbol, PERIOD_M15, prevDayData[i].lowTime, true);
|
|
prevDayData[i].lowPrice = iLow(symbol, PERIOD_M15, prevDayData[i].lowIndex);
|
|
}
|
|
|
|
prevDayData[i].highTime = GetM15PrevDayHighTime(symbol);
|
|
if(prevDayData[i].highTime > 0)
|
|
{
|
|
prevDayData[i].highIndex = iBarShift(symbol, PERIOD_M15, prevDayData[i].highTime, true);
|
|
prevDayData[i].highPrice = iHigh(symbol, PERIOD_M15, prevDayData[i].highIndex);
|
|
}
|
|
|
|
// Debug print for previous day values
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Symbol=", symbol,
|
|
" PrevDayHigh=", prevDayData[i].highPrice,
|
|
" at ", TimeToString(prevDayData[i].highTime),
|
|
" PrevDayLow=", prevDayData[i].lowPrice,
|
|
" at ", TimeToString(prevDayData[i].lowTime));
|
|
}
|
|
|
|
// Reset swing arrays for fresh analysis
|
|
ArrayResize(swingData[i].swingLowPrices, 0);
|
|
ArrayResize(swingData[i].swingLowTimes, 0);
|
|
ArrayResize(swingData[i].swingHighPrices, 0);
|
|
ArrayResize(swingData[i].swingHighTimes, 0);
|
|
|
|
// Core analysis functions for THIS symbol
|
|
FindSwingPoints(i); // Find swing highs and lows
|
|
GetConsecutiveHighsAndLows(i); // Identify consecutive swings
|
|
GetBreakPoint(i); // Determine breakout points
|
|
|
|
// Validate patterns against previous day levels
|
|
ValidatePatterns(i);
|
|
}
|
|
|
|
// Update market bias based on daily price action for THIS symbol
|
|
FindBias(i);
|
|
|
|
// Check for ORIGINAL alert conditions (UNCHANGED)
|
|
CheckOriginalAlerts(i);
|
|
|
|
// Check for retracement alerts (NEW - separate monitoring)
|
|
CheckRetracementAlerts(i);
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// TRADE EXECUTION FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate position size based on risk percentage |
|
|
//+------------------------------------------------------------------+
|
|
double CalculatePositionSize(string symbol, double entryPrice, double stopLossPrice, ENUM_ORDER_TYPE orderType)
|
|
{
|
|
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
double riskAmount = accountBalance * (MaxRiskPercent / 100.0);
|
|
|
|
double pointValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
|
double stopDistancePoints = MathAbs(entryPrice - stopLossPrice) / tickSize;
|
|
double riskPerLot = stopDistancePoints * pointValue;
|
|
|
|
if(riskPerLot <= 0)
|
|
return LotSize; // Return default lot size if calculation fails
|
|
|
|
double lotSize = riskAmount / riskPerLot;
|
|
|
|
// Normalize lot size
|
|
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
|
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
|
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
|
|
|
lotSize = MathFloor(lotSize / lotStep) * lotStep;
|
|
lotSize = MathMax(minLot, MathMin(maxLot, lotSize));
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Position size calculation for ", symbol);
|
|
Print("DEBUG: Entry: ", entryPrice, " SL: ", stopLossPrice);
|
|
Print("DEBUG: Stop distance points: ", stopDistancePoints);
|
|
Print("DEBUG: Risk amount: ", riskAmount);
|
|
Print("DEBUG: Calculated lot size: ", lotSize);
|
|
}
|
|
|
|
return lotSize;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Execute bullish market buy trade |
|
|
//+------------------------------------------------------------------+
|
|
bool ExecuteBullishTrade(int symbolIndex)
|
|
{
|
|
if(!EnableAutoTrading)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Auto-trading disabled, skipping bullish trade for ", Symbols[symbolIndex]);
|
|
return false;
|
|
}
|
|
|
|
string symbol = Symbols[symbolIndex];
|
|
double entryPrice = retraceTrackers[symbolIndex].bullishFortyPercentLevel;
|
|
double stopLoss = retraceTrackers[symbolIndex].bullishBPrice;
|
|
double takeProfit = retraceTrackers[symbolIndex].bullishSwingHigh;
|
|
|
|
// Calculate position size
|
|
double lotSize = CalculatePositionSize(symbol, entryPrice, stopLoss, ORDER_TYPE_BUY);
|
|
|
|
// Ensure price is normalized
|
|
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
entryPrice = NormalizeDouble(entryPrice, digits);
|
|
stopLoss = NormalizeDouble(stopLoss, digits);
|
|
takeProfit = NormalizeDouble(takeProfit, digits);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Executing BULLISH MARKET BUY for ", symbol);
|
|
Print("DEBUG: Entry (40% level): ", entryPrice);
|
|
Print("DEBUG: Stop Loss (B price): ", stopLoss);
|
|
Print("DEBUG: Take Profit (Swing High): ", takeProfit);
|
|
Print("DEBUG: Lot Size: ", lotSize);
|
|
}
|
|
|
|
// Set slippage
|
|
trade.SetDeviationInPoints(10);
|
|
|
|
// Open buy market order
|
|
bool result = trade.Buy(lotSize, symbol, entryPrice, stopLoss, takeProfit, "TurtleSoup Bullish Setup");
|
|
|
|
if(result)
|
|
{
|
|
retraceTrackers[symbolIndex].bullishTradeTicket = trade.ResultDeal();
|
|
retraceTrackers[symbolIndex].bullishTradeState = TRADE_EXECUTED;
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: SUCCESS - Bullish trade executed! Ticket: ", retraceTrackers[symbolIndex].bullishTradeTicket);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: FAILED - Bullish trade execution failed. Error: ", GetLastError());
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Execute bearish market sell trade |
|
|
//+------------------------------------------------------------------+
|
|
bool ExecuteBearishTrade(int symbolIndex)
|
|
{
|
|
if(!EnableAutoTrading)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Auto-trading disabled, skipping bearish trade for ", Symbols[symbolIndex]);
|
|
return false;
|
|
}
|
|
|
|
string symbol = Symbols[symbolIndex];
|
|
double entryPrice = retraceTrackers[symbolIndex].bearishFortyPercentLevel;
|
|
double stopLoss = retraceTrackers[symbolIndex].bearishBPrice;
|
|
double takeProfit = retraceTrackers[symbolIndex].bearishSwingLow;
|
|
|
|
// Calculate position size
|
|
double lotSize = CalculatePositionSize(symbol, entryPrice, stopLoss, ORDER_TYPE_SELL);
|
|
|
|
// Ensure price is normalized
|
|
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
entryPrice = NormalizeDouble(entryPrice, digits);
|
|
stopLoss = NormalizeDouble(stopLoss, digits);
|
|
takeProfit = NormalizeDouble(takeProfit, digits);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Executing BEARISH MARKET SELL for ", symbol);
|
|
Print("DEBUG: Entry (40% level): ", entryPrice);
|
|
Print("DEBUG: Stop Loss (B price): ", stopLoss);
|
|
Print("DEBUG: Take Profit (Swing Low): ", takeProfit);
|
|
Print("DEBUG: Lot Size: ", lotSize);
|
|
}
|
|
|
|
// Set slippage
|
|
trade.SetDeviationInPoints(10);
|
|
|
|
// Open sell market order
|
|
bool result = trade.Sell(lotSize, symbol, entryPrice, stopLoss, takeProfit, "TurtleSoup Bearish Setup");
|
|
|
|
if(result)
|
|
{
|
|
retraceTrackers[symbolIndex].bearishTradeTicket = trade.ResultDeal();
|
|
retraceTrackers[symbolIndex].bearishTradeState = TRADE_EXECUTED;
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: SUCCESS - Bearish trade executed! Ticket: ", retraceTrackers[symbolIndex].bearishTradeTicket);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: FAILED - Bearish trade execution failed. Error: ", GetLastError());
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// ORIGINAL ALERT FUNCTION - COMPLETELY UNCHANGED
|
|
// ============================================================
|
|
//+------------------------------------------------------------------+
|
|
//| Original alert monitoring (unchanged from version 1.3) |
|
|
//+------------------------------------------------------------------+
|
|
void CheckOriginalAlerts(int symbolIndex)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
// Get close price of previous candle for gap detection
|
|
double closeLastCandle = iClose(symbol, PERIOD_M15, 1);
|
|
|
|
// BULLISH ALERT CONDITION (ORIGINAL - UNCHANGED)
|
|
if(biasData[symbolIndex].bias == BIAS_BULLISH &&
|
|
swingData[symbolIndex].bullishPatternValid && // Check PDL validation
|
|
swingData[symbolIndex].currentBidPrice > swingData[symbolIndex].bullishSwingHigh &&
|
|
closeLastCandle < swingData[symbolIndex].bullishSwingHigh &&
|
|
swingData[symbolIndex].bullishSwingHigh != alertTrackers[symbolIndex].lastBullishSwingHigh &&
|
|
alertTrackers[symbolIndex].bullishAlertSent == false &&
|
|
alertTrackers[symbolIndex].bullishAlertCount < 1)
|
|
{
|
|
datetime timeNow = TimeCurrent();
|
|
|
|
// Perform enhanced validations
|
|
swingData[symbolIndex].bullishBIsLowest = ValidateBullishBIsLowest(symbolIndex, timeNow);
|
|
swingData[symbolIndex].bullishAIsHighest = ValidateBullishAIsHighest(symbolIndex, timeNow);
|
|
|
|
// Validate price action: No trading above bullishSwingHigh before trigger
|
|
int barsBetweenSwingHighAndTrigger = GetBarsBetweenTimes(swingData[symbolIndex].bullishSwingHighTime, timeNow, symbol);
|
|
int barsBetweenFirstLowAndTrigger = GetBarsBetweenTimes(swingData[symbolIndex].Last_LL_Times[0], timeNow, symbol);
|
|
bool allBarsValid = true;
|
|
|
|
// Check all bars between swing high and trigger time
|
|
for(int b = barsBetweenSwingHighAndTrigger - 1; b >= 1; b--)
|
|
{
|
|
if(iHigh(symbol, PERIOD_M15, b) >= swingData[symbolIndex].bullishSwingHigh)
|
|
{
|
|
allBarsValid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check all bars between first low and trigger time
|
|
for(int b = barsBetweenFirstLowAndTrigger; b >= 0; b--)
|
|
{
|
|
if(iLow(symbol, PERIOD_M15, b) < swingData[symbolIndex].Last_LL_Prices[1])
|
|
{
|
|
allBarsValid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If all validations pass, trigger bullish alert
|
|
if(allBarsValid && swingData[symbolIndex].bullishBIsLowest && swingData[symbolIndex].bullishAIsHighest)
|
|
{
|
|
// Update alert state for THIS SYMBOL (ORIGINAL)
|
|
alertTrackers[symbolIndex].bullishAlertSent = true;
|
|
alertTrackers[symbolIndex].bullishAlertCount++;
|
|
alertTrackers[symbolIndex].lastBullishSwingHigh = swingData[symbolIndex].bullishSwingHigh;
|
|
alertTrackers[symbolIndex].bullishAlertTime = TimeCurrent(); // STORE C TIME - NEVER CHANGES
|
|
|
|
// SAVE DATA FOR RETRACEMENT ALERT (NEW)
|
|
SaveBullishRetracementData(symbolIndex);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: BULLISH BREAKOUT ALERT for ", symbol, " at ", TimeToString(timeNow));
|
|
Print("DEBUG: Pattern validation: PASSED (B <= PDL)");
|
|
Print("DEBUG: Enhanced validations: B is lowest ✓, A is highest ✓");
|
|
Print("DEBUG: Swing High Price (A): ", swingData[symbolIndex].bullishSwingHigh,
|
|
" Time: ", TimeToString(swingData[symbolIndex].bullishSwingHighTime));
|
|
Print("DEBUG: B Point Price: ", swingData[symbolIndex].Last_LL_Prices[1]);
|
|
Print("DEBUG: Market Bid Price: ", swingData[symbolIndex].currentBidPrice);
|
|
Print("DEBUG: Alert #", alertTrackers[symbolIndex].bullishAlertCount, " for today");
|
|
Print("DEBUG: C time FIXED at: ", TimeToString(alertTrackers[symbolIndex].bullishAlertTime));
|
|
Print("DEBUG: Now monitoring for retracement to 40% level...");
|
|
}
|
|
|
|
// Capture chart state using BREAKOUT annotations
|
|
string screenshotFilename = TakeScreenshot("Bullish_Breakout", symbol, symbolIndex);
|
|
|
|
// Generate unique identifier
|
|
string uniqueId = GenerateUniqueId();
|
|
|
|
// Send alert data (ORIGINAL - UNCHANGED)
|
|
SendAlertData("bullish",
|
|
swingData[symbolIndex].bullishSwingHigh,
|
|
swingData[symbolIndex].bullishSwingHighTime,
|
|
alertTrackers[symbolIndex].bullishAlertTime,
|
|
screenshotFilename, uniqueId, symbol, symbolIndex);
|
|
|
|
// Send screenshot
|
|
if(screenshotFilename != "")
|
|
SendScreenshotBinary(screenshotFilename, "bullish", uniqueId, symbol, symbolIndex);
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish alert conditions met but enhanced validations failed for ", symbol);
|
|
Print("DEBUG: B is lowest: ", swingData[symbolIndex].bullishBIsLowest ? "✓" : "✗");
|
|
Print("DEBUG: A is highest: ", swingData[symbolIndex].bullishAIsHighest ? "✓" : "✗");
|
|
Print("DEBUG: Price action valid: ", allBarsValid ? "✓" : "✗");
|
|
}
|
|
}
|
|
}
|
|
|
|
// BEARISH ALERT CONDITION (ORIGINAL - UNCHANGED)
|
|
if(biasData[symbolIndex].bias == BIAS_BEARISH &&
|
|
swingData[symbolIndex].bearishPatternValid && // Check PDH validation
|
|
swingData[symbolIndex].currentAskPrice < swingData[symbolIndex].bearishSwingLow &&
|
|
closeLastCandle > swingData[symbolIndex].bearishSwingLow &&
|
|
swingData[symbolIndex].bearishSwingLow != alertTrackers[symbolIndex].lastBearishSwingLow &&
|
|
alertTrackers[symbolIndex].bearishAlertSent == false &&
|
|
alertTrackers[symbolIndex].bearishAlertCount < 1)
|
|
{
|
|
datetime timeNow = TimeCurrent();
|
|
|
|
// Perform enhanced validations
|
|
swingData[symbolIndex].bearishBIsHighest = ValidateBearishBIsHighest(symbolIndex, timeNow);
|
|
swingData[symbolIndex].bearishAIsLowest = ValidateBearishAIsLowest(symbolIndex, timeNow);
|
|
|
|
// Validate price action: No trading below bearishSwingLow before trigger
|
|
int barsBetweenSwingLowAndTrigger = GetBarsBetweenTimes(swingData[symbolIndex].bearishSwingLowTime, timeNow, symbol);
|
|
int barsBetweenFirstHighAndTrigger = GetBarsBetweenTimes(swingData[symbolIndex].Last_HH_Times[0], timeNow, symbol);
|
|
bool allBarsValid = true;
|
|
|
|
// Check all bars between swing low and trigger time
|
|
for(int b = barsBetweenSwingLowAndTrigger - 1; b >= 1; b--)
|
|
{
|
|
if(iLow(symbol, PERIOD_M15, b) <= swingData[symbolIndex].bearishSwingLow)
|
|
{
|
|
allBarsValid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check all bars between first high and trigger time
|
|
for(int b = barsBetweenFirstHighAndTrigger; b >= 0; b--)
|
|
{
|
|
if(iHigh(symbol, PERIOD_M15, b) > swingData[symbolIndex].Last_HH_Prices[1])
|
|
{
|
|
allBarsValid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If all validations pass, trigger bearish alert
|
|
if(allBarsValid && swingData[symbolIndex].bearishBIsHighest && swingData[symbolIndex].bearishAIsLowest)
|
|
{
|
|
// Update alert state for THIS SYMBOL (ORIGINAL)
|
|
alertTrackers[symbolIndex].bearishAlertSent = true;
|
|
alertTrackers[symbolIndex].bearishAlertCount++;
|
|
alertTrackers[symbolIndex].lastBearishSwingLow = swingData[symbolIndex].bearishSwingLow;
|
|
alertTrackers[symbolIndex].bearishAlertTime = TimeCurrent(); // STORE C TIME - NEVER CHANGES
|
|
|
|
// SAVE DATA FOR RETRACEMENT ALERT (NEW)
|
|
SaveBearishRetracementData(symbolIndex);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: BEARISH BREAKOUT ALERT for ", symbol, " at ", TimeToString(timeNow));
|
|
Print("DEBUG: Pattern validation: PASSED (B >= PDH)");
|
|
Print("DEBUG: Enhanced validations: B is highest ✓, A is lowest ✓");
|
|
Print("DEBUG: Swing Low Price (A): ", swingData[symbolIndex].bearishSwingLow,
|
|
" Time: ", TimeToString(swingData[symbolIndex].bearishSwingLowTime));
|
|
Print("DEBUG: B Point Price: ", swingData[symbolIndex].Last_HH_Prices[1]);
|
|
Print("DEBUG: Market Ask Price: ", swingData[symbolIndex].currentAskPrice);
|
|
Print("DEBUG: Alert #", alertTrackers[symbolIndex].bearishAlertCount, " for today");
|
|
Print("DEBUG: C time FIXED at: ", TimeToString(alertTrackers[symbolIndex].bearishAlertTime));
|
|
Print("DEBUG: Now monitoring for retracement to 40% level...");
|
|
}
|
|
|
|
// Capture chart state using BREAKOUT annotations
|
|
string screenshotFilename = TakeScreenshot("Bearish_Breakout", symbol, symbolIndex);
|
|
|
|
// Generate unique identifier
|
|
string uniqueId = GenerateUniqueId();
|
|
|
|
// Send alert data (ORIGINAL - UNCHANGED)
|
|
SendAlertData("bearish",
|
|
swingData[symbolIndex].bearishSwingLow,
|
|
swingData[symbolIndex].bearishSwingLowTime,
|
|
alertTrackers[symbolIndex].bearishAlertTime,
|
|
screenshotFilename, uniqueId, symbol, symbolIndex);
|
|
|
|
// Send screenshot
|
|
if(screenshotFilename != "")
|
|
SendScreenshotBinary(screenshotFilename, "bearish", uniqueId, symbol, symbolIndex);
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish alert conditions met but enhanced validations failed for ", symbol);
|
|
Print("DEBUG: B is highest: ", swingData[symbolIndex].bearishBIsHighest ? "✓" : "✗");
|
|
Print("DEBUG: A is lowest: ", swingData[symbolIndex].bearishAIsLowest ? "✓" : "✗");
|
|
Print("DEBUG: Price action valid: ", allBarsValid ? "✓" : "✗");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// NEW RETRACEMENT DATA SAVING FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Save bullish data for retracement alert |
|
|
//+------------------------------------------------------------------+
|
|
void SaveBullishRetracementData(int symbolIndex)
|
|
{
|
|
retraceTrackers[symbolIndex].bullishBreakoutOccurred = true;
|
|
retraceTrackers[symbolIndex].bullishBreakoutTime = alertTrackers[symbolIndex].bullishAlertTime;
|
|
retraceTrackers[symbolIndex].bullishBreakoutPrice = swingData[symbolIndex].bullishSwingHigh;
|
|
retraceTrackers[symbolIndex].bullishBPrice = swingData[symbolIndex].Last_LL_Prices[1];
|
|
retraceTrackers[symbolIndex].bullishSwingHigh = swingData[symbolIndex].bullishSwingHigh;
|
|
retraceTrackers[symbolIndex].bullishSwingHighTime = swingData[symbolIndex].bullishSwingHighTime;
|
|
retraceTrackers[symbolIndex].bullishTradeState = TRADE_PENDING;
|
|
|
|
// Calculate 40% level
|
|
double moveDistance = swingData[symbolIndex].bullishSwingHigh - swingData[symbolIndex].Last_LL_Prices[1];
|
|
retraceTrackers[symbolIndex].bullishFortyPercentLevel = swingData[symbolIndex].Last_LL_Prices[1] + (moveDistance * 0.40);
|
|
|
|
// Save swing point data
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Prices[0] = swingData[symbolIndex].Last_LL_Prices[0];
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Prices[1] = swingData[symbolIndex].Last_LL_Prices[1];
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Times[0] = swingData[symbolIndex].Last_LL_Times[0];
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Times[1] = swingData[symbolIndex].Last_LL_Times[1];
|
|
retraceTrackers[symbolIndex].bullishLast_HH_Prices[0] = swingData[symbolIndex].Last_HH_Prices[0];
|
|
retraceTrackers[symbolIndex].bullishLast_HH_Prices[1] = swingData[symbolIndex].Last_HH_Prices[1];
|
|
retraceTrackers[symbolIndex].bullishLast_HH_Times[0] = swingData[symbolIndex].Last_HH_Times[0];
|
|
retraceTrackers[symbolIndex].bullishLast_HH_Times[1] = swingData[symbolIndex].Last_HH_Times[1];
|
|
|
|
// Save previous day data
|
|
retraceTrackers[symbolIndex].bullishPrevDayLow = prevDayData[symbolIndex].lowPrice;
|
|
retraceTrackers[symbolIndex].bullishPrevDayLowTime = prevDayData[symbolIndex].lowTime;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Save bearish data for retracement alert |
|
|
//+------------------------------------------------------------------+
|
|
void SaveBearishRetracementData(int symbolIndex)
|
|
{
|
|
retraceTrackers[symbolIndex].bearishBreakoutOccurred = true;
|
|
retraceTrackers[symbolIndex].bearishBreakoutTime = alertTrackers[symbolIndex].bearishAlertTime;
|
|
retraceTrackers[symbolIndex].bearishBreakoutPrice = swingData[symbolIndex].bearishSwingLow;
|
|
retraceTrackers[symbolIndex].bearishBPrice = swingData[symbolIndex].Last_HH_Prices[1];
|
|
retraceTrackers[symbolIndex].bearishSwingLow = swingData[symbolIndex].bearishSwingLow;
|
|
retraceTrackers[symbolIndex].bearishSwingLowTime = swingData[symbolIndex].bearishSwingLowTime;
|
|
retraceTrackers[symbolIndex].bearishTradeState = TRADE_PENDING;
|
|
|
|
// Calculate 40% level
|
|
double moveDistance = swingData[symbolIndex].Last_HH_Prices[1] - swingData[symbolIndex].bearishSwingLow;
|
|
retraceTrackers[symbolIndex].bearishFortyPercentLevel = swingData[symbolIndex].Last_HH_Prices[1] - (moveDistance * 0.40);
|
|
|
|
// Save swing point data
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Prices[0] = swingData[symbolIndex].Last_HH_Prices[0];
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Prices[1] = swingData[symbolIndex].Last_HH_Prices[1];
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Times[0] = swingData[symbolIndex].Last_HH_Times[0];
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Times[1] = swingData[symbolIndex].Last_HH_Times[1];
|
|
retraceTrackers[symbolIndex].bearishLast_LL_Prices[0] = swingData[symbolIndex].Last_LL_Prices[0];
|
|
retraceTrackers[symbolIndex].bearishLast_LL_Prices[1] = swingData[symbolIndex].Last_LL_Prices[1];
|
|
retraceTrackers[symbolIndex].bearishLast_LL_Times[0] = swingData[symbolIndex].Last_LL_Times[0];
|
|
retraceTrackers[symbolIndex].bearishLast_LL_Times[1] = swingData[symbolIndex].Last_LL_Times[1];
|
|
|
|
// Save previous day data
|
|
retraceTrackers[symbolIndex].bearishPrevDayHigh = prevDayData[symbolIndex].highPrice;
|
|
retraceTrackers[symbolIndex].bearishPrevDayHighTime = prevDayData[symbolIndex].highTime;
|
|
}
|
|
|
|
// ============================================================
|
|
// NEW RETRACEMENT ALERT MONITORING WITH TRADE EXECUTION
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for retracement alerts (separate monitoring) |
|
|
//+------------------------------------------------------------------+
|
|
void CheckRetracementAlerts(int symbolIndex)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
// Check for bullish retracement
|
|
if(retraceTrackers[symbolIndex].bullishBreakoutOccurred &&
|
|
retraceTrackers[symbolIndex].bullishTradeState == TRADE_PENDING)
|
|
{
|
|
// Monitor for retracement to 40% level
|
|
if(swingData[symbolIndex].currentBidPrice <= retraceTrackers[symbolIndex].bullishFortyPercentLevel)
|
|
{
|
|
datetime timeNow = TimeCurrent();
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: BULLISH RETRACEMENT ALERT for ", symbol, " at ", TimeToString(timeNow));
|
|
Print("DEBUG: Price retraced to 40% level: ", retraceTrackers[symbolIndex].bullishFortyPercentLevel);
|
|
Print("DEBUG: Original breakout at: ", TimeToString(retraceTrackers[symbolIndex].bullishBreakoutTime));
|
|
}
|
|
|
|
// EXECUTE TRADE AT MARKET ON RETRACEMENT
|
|
ExecuteBullishTrade(symbolIndex);
|
|
|
|
// Capture chart state using RETRACEMENT annotations
|
|
string screenshotFilename = TakeScreenshot("Bullish_Retracement", symbol, symbolIndex);
|
|
|
|
// Generate unique identifier
|
|
string uniqueId = GenerateUniqueId();
|
|
|
|
// Send alert data (same payload structure)
|
|
SendAlertData("bullish_retracement",
|
|
retraceTrackers[symbolIndex].bullishSwingHigh,
|
|
retraceTrackers[symbolIndex].bullishSwingHighTime,
|
|
timeNow,
|
|
screenshotFilename, uniqueId, symbol, symbolIndex);
|
|
|
|
// Send screenshot
|
|
if(screenshotFilename != "")
|
|
SendScreenshotBinary(screenshotFilename, "bullish_retracement", uniqueId, symbol, symbolIndex);
|
|
|
|
// Don't reset flag - keep as executed to prevent re-triggering
|
|
}
|
|
}
|
|
|
|
// Check for bearish retracement
|
|
if(retraceTrackers[symbolIndex].bearishBreakoutOccurred &&
|
|
retraceTrackers[symbolIndex].bearishTradeState == TRADE_PENDING)
|
|
{
|
|
// Monitor for retracement to 40% level
|
|
if(swingData[symbolIndex].currentAskPrice >= retraceTrackers[symbolIndex].bearishFortyPercentLevel)
|
|
{
|
|
datetime timeNow = TimeCurrent();
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: BEARISH RETRACEMENT ALERT for ", symbol, " at ", TimeToString(timeNow));
|
|
Print("DEBUG: Price retraced to 40% level: ", retraceTrackers[symbolIndex].bearishFortyPercentLevel);
|
|
Print("DEBUG: Original breakout at: ", TimeToString(retraceTrackers[symbolIndex].bearishBreakoutTime));
|
|
}
|
|
|
|
// EXECUTE TRADE AT MARKET ON RETRACEMENT
|
|
ExecuteBearishTrade(symbolIndex);
|
|
|
|
// Capture chart state using RETRACEMENT annotations
|
|
string screenshotFilename = TakeScreenshot("Bearish_Retracement", symbol, symbolIndex);
|
|
|
|
// Generate unique identifier
|
|
string uniqueId = GenerateUniqueId();
|
|
|
|
// Send alert data (same payload structure)
|
|
SendAlertData("bearish_retracement",
|
|
retraceTrackers[symbolIndex].bearishSwingLow,
|
|
retraceTrackers[symbolIndex].bearishSwingLowTime,
|
|
timeNow,
|
|
screenshotFilename, uniqueId, symbol, symbolIndex);
|
|
|
|
// Send screenshot
|
|
if(screenshotFilename != "")
|
|
SendScreenshotBinary(screenshotFilename, "bearish_retracement", uniqueId, symbol, symbolIndex);
|
|
|
|
// Don't reset flag - keep as executed to prevent re-triggering
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// FUNCTION: Validate patterns against previous day levels
|
|
// ============================================================
|
|
//+------------------------------------------------------------------+
|
|
//| Validate bullish and bearish patterns against PDH/PDL |
|
|
//+------------------------------------------------------------------+
|
|
void ValidatePatterns(int symbolIndex)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
// Reset validity flags
|
|
swingData[symbolIndex].bullishPatternValid = false;
|
|
swingData[symbolIndex].bearishPatternValid = false;
|
|
|
|
// Check if we have valid swing points and previous day data
|
|
bool hasBullishSwings = (swingData[symbolIndex].Last_LL_Prices[0] > 0 &&
|
|
swingData[symbolIndex].Last_LL_Prices[1] > 0);
|
|
bool hasBearishSwings = (swingData[symbolIndex].Last_HH_Prices[0] > 0 &&
|
|
swingData[symbolIndex].Last_HH_Prices[1] > 0);
|
|
bool hasPrevDayData = (prevDayData[symbolIndex].lowPrice > 0 &&
|
|
prevDayData[symbolIndex].highPrice > 0);
|
|
|
|
if(!hasPrevDayData)
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Cannot validate patterns for ", symbol, " - Previous day data missing");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Validate BULLISH pattern
|
|
if(hasBullishSwings)
|
|
{
|
|
// Bullish pattern is VALID only if Last_LL_Prices[1] (B point) is LESS THAN or equal to previous day low
|
|
if(swingData[symbolIndex].Last_LL_Prices[1] <= prevDayData[symbolIndex].lowPrice)
|
|
{
|
|
swingData[symbolIndex].bullishPatternValid = true;
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish pattern VALID for ", symbol);
|
|
Print("DEBUG: B point (LL2): ", swingData[symbolIndex].Last_LL_Prices[1]);
|
|
Print("DEBUG: PDL: ", prevDayData[symbolIndex].lowPrice);
|
|
Print("DEBUG: Condition: B <= PDL ✓");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish pattern INVALID for ", symbol);
|
|
Print("DEBUG: B point (LL2): ", swingData[symbolIndex].Last_LL_Prices[1]);
|
|
Print("DEBUG: PDL: ", prevDayData[symbolIndex].lowPrice);
|
|
Print("DEBUG: Condition failed: B > PDL");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate BEARISH pattern
|
|
if(hasBearishSwings)
|
|
{
|
|
// Bearish pattern is VALID only if Last_HH_Prices[1] (B point) is GREATER THAN or equal to previous day high
|
|
if(swingData[symbolIndex].Last_HH_Prices[1] >= prevDayData[symbolIndex].highPrice)
|
|
{
|
|
swingData[symbolIndex].bearishPatternValid = true;
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish pattern VALID for ", symbol);
|
|
Print("DEBUG: B point (HH2): ", swingData[symbolIndex].Last_HH_Prices[1]);
|
|
Print("DEBUG: PDH: ", prevDayData[symbolIndex].highPrice);
|
|
Print("DEBUG: Condition: B >= PDH ✓");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish pattern INVALID for ", symbol);
|
|
Print("DEBUG: B point (HH2): ", swingData[symbolIndex].Last_HH_Prices[1]);
|
|
Print("DEBUG: PDH: ", prevDayData[symbolIndex].highPrice);
|
|
Print("DEBUG: Condition failed: B < PDH");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// ENHANCED VALIDATION FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Validate Bullish B is Lowest Low between SSL and C |
|
|
//+------------------------------------------------------------------+
|
|
bool ValidateBullishBIsLowest(int symbolIndex, datetime triggerTime)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
double bPrice = swingData[symbolIndex].Last_LL_Prices[1];
|
|
datetime sslTime = swingData[symbolIndex].Last_LL_Times[0];
|
|
|
|
// Get bar indices
|
|
int sslBar = iBarShift(symbol, PERIOD_M15, sslTime, true);
|
|
int triggerBar = iBarShift(symbol, PERIOD_M15, triggerTime, true);
|
|
|
|
if(sslBar < 0 || triggerBar < 0 || sslBar <= triggerBar)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Cannot validate bullish B - invalid bar indices");
|
|
return false;
|
|
}
|
|
|
|
// Check all bars between SSL and C (inclusive)
|
|
for(int bar = sslBar; bar >= triggerBar; bar--)
|
|
{
|
|
double barLow = iLow(symbol, PERIOD_M15, bar);
|
|
if(barLow < bPrice - 0.00001) // Allow small floating point tolerance
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish B validation FAILED - found lower low at bar ", bar);
|
|
Print("DEBUG: B price: ", bPrice, " Lower low: ", barLow);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish B validation PASSED - B is the lowest low between SSL and C");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Validate Bullish A is Highest High between A and C+1 |
|
|
//+------------------------------------------------------------------+
|
|
bool ValidateBullishAIsHighest(int symbolIndex, datetime triggerTime)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
double aPrice = swingData[symbolIndex].bullishSwingHigh;
|
|
datetime aTime = swingData[symbolIndex].bullishSwingHighTime;
|
|
|
|
// C+1 is the candle before trigger (higher bar index)
|
|
int triggerBar = iBarShift(symbol, PERIOD_M15, triggerTime, true);
|
|
int aBar = iBarShift(symbol, PERIOD_M15, aTime, true);
|
|
int cPlus1Bar = triggerBar + 1; // C+1 is one bar earlier
|
|
|
|
if(aBar < 0 || triggerBar < 0 || aBar <= cPlus1Bar)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Cannot validate bullish A - invalid bar indices");
|
|
return false;
|
|
}
|
|
|
|
// Check all bars between A and C+1 (inclusive)
|
|
for(int bar = aBar; bar >= cPlus1Bar; bar--)
|
|
{
|
|
double barHigh = iHigh(symbol, PERIOD_M15, bar);
|
|
if(barHigh > aPrice + 0.00001) // Allow small floating point tolerance
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish A validation FAILED - found higher high at bar ", bar);
|
|
Print("DEBUG: A price: ", aPrice, " Higher high: ", barHigh);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish A validation PASSED - A is the highest high between A and C+1");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Validate Bearish B is Highest High between BSL and C |
|
|
//+------------------------------------------------------------------+
|
|
bool ValidateBearishBIsHighest(int symbolIndex, datetime triggerTime)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
double bPrice = swingData[symbolIndex].Last_HH_Prices[1];
|
|
datetime bslTime = swingData[symbolIndex].Last_HH_Times[0];
|
|
|
|
// Get bar indices
|
|
int bslBar = iBarShift(symbol, PERIOD_M15, bslTime, true);
|
|
int triggerBar = iBarShift(symbol, PERIOD_M15, triggerTime, true);
|
|
|
|
if(bslBar < 0 || triggerBar < 0 || bslBar <= triggerBar)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Cannot validate bearish B - invalid bar indices");
|
|
return false;
|
|
}
|
|
|
|
// Check all bars between BSL and C (inclusive)
|
|
for(int bar = bslBar; bar >= triggerBar; bar--)
|
|
{
|
|
double barHigh = iHigh(symbol, PERIOD_M15, bar);
|
|
if(barHigh > bPrice + 0.00001) // Allow small floating point tolerance
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish B validation FAILED - found higher high at bar ", bar);
|
|
Print("DEBUG: B price: ", bPrice, " Higher high: ", barHigh);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish B validation PASSED - B is the highest high between BSL and C");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Validate Bearish A is Lowest Low between A and C+1 |
|
|
//+------------------------------------------------------------------+
|
|
bool ValidateBearishAIsLowest(int symbolIndex, datetime triggerTime)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
double aPrice = swingData[symbolIndex].bearishSwingLow;
|
|
datetime aTime = swingData[symbolIndex].bearishSwingLowTime;
|
|
|
|
// C+1 is the candle before trigger (higher bar index)
|
|
int triggerBar = iBarShift(symbol, PERIOD_M15, triggerTime, true);
|
|
int aBar = iBarShift(symbol, PERIOD_M15, aTime, true);
|
|
int cPlus1Bar = triggerBar + 1; // C+1 is one bar earlier
|
|
|
|
if(aBar < 0 || triggerBar < 0 || aBar <= cPlus1Bar)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Cannot validate bearish A - invalid bar indices");
|
|
return false;
|
|
}
|
|
|
|
// Check all bars between A and C+1 (inclusive)
|
|
for(int bar = aBar; bar >= cPlus1Bar; bar--)
|
|
{
|
|
double barLow = iLow(symbol, PERIOD_M15, bar);
|
|
if(barLow < aPrice - 0.00001) // Allow small floating point tolerance
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish A validation FAILED - found lower low at bar ", bar);
|
|
Print("DEBUG: A price: ", aPrice, " Lower low: ", barLow);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish A validation PASSED - A is the lowest low between A and C+1");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ============================================================
|
|
// ALERT MANAGEMENT FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Generate a unique identifier |
|
|
//+------------------------------------------------------------------+
|
|
string GenerateUniqueId()
|
|
{
|
|
int randomNum = (int)MathRand();
|
|
string uniqueId = IntegerToString(TimeCurrent()) + "_" + IntegerToString(randomNum) + "_" + IntegerToString(GetTickCount());
|
|
return uniqueId;
|
|
}
|
|
|
|
// ============================================================
|
|
// CHART OBJECT MANAGEMENT FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Delete all chart objects |
|
|
//+------------------------------------------------------------------+
|
|
void DeleteAllObjects()
|
|
{
|
|
int totalObjects = ObjectsTotal(0, 0, -1);
|
|
bool objectsDeleted = false;
|
|
|
|
for(int i = totalObjects - 1; i >= 0; i--)
|
|
{
|
|
string objName = ObjectName(0, i, 0, -1);
|
|
|
|
if(StringFind(objName, "BullishTrend_") == 0 || StringFind(objName, "BearishTrend_") == 0 ||
|
|
StringFind(objName, "BSL_") == 0 || StringFind(objName, "SSL_") == 0 ||
|
|
StringFind(objName, "PDL_") == 0 || StringFind(objName, "PDH_") == 0 ||
|
|
StringFind(objName, "PDH") == 0 || StringFind(objName, "PDL") == 0 ||
|
|
StringFind(objName, "bearishSwingLow") == 0 || StringFind(objName, "bullishSwingHigh") == 0 ||
|
|
StringFind(objName, "H2") == 0 || StringFind(objName, "L2") == 0 ||
|
|
StringFind(objName, "triggerPoint") == 0)
|
|
{
|
|
ObjectDelete(0, objName);
|
|
objectsDeleted = true;
|
|
}
|
|
}
|
|
|
|
if(EnableDebugPrints && objectsDeleted)
|
|
{
|
|
Print("DEBUG: Deleted all chart objects. Total objects removed: ", totalObjects);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Draw bullish BREAKOUT annotations (identical to original) |
|
|
//+------------------------------------------------------------------+
|
|
void DrawBullishBreakoutAnnotations(long chart_id, string symbol, int symbolIndex)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Drawing bullish BREAKOUT annotations on chart ID: ", chart_id, " for ", symbol);
|
|
|
|
// USE STORED ALERT TIME - THIS NEVER CHANGES!
|
|
datetime timeNow = alertTrackers[symbolIndex].bullishAlertTime;
|
|
|
|
if(timeNow == 0)
|
|
{
|
|
Print("ERROR: Bullish alert time not set for ", symbol);
|
|
return;
|
|
}
|
|
|
|
// 1. Draw Previous Day Low (PDL) Trendline
|
|
string PDL_Linename = "PDL_Bullish_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, PDL_Linename, OBJ_TREND, 0,
|
|
prevDayData[symbolIndex].lowTime, prevDayData[symbolIndex].lowPrice,
|
|
swingData[symbolIndex].Last_LL_Times[0], prevDayData[symbolIndex].lowPrice);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_WIDTH, 3);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, PDL_Linename, OBJPROP_TEXT, "PDL Trend");
|
|
|
|
// 2. Draw SSL (Swing Structure Low) Trendline
|
|
string SSL_Linename = "SSL_Bullish_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, SSL_Linename, OBJ_TREND, 0,
|
|
swingData[symbolIndex].Last_LL_Times[0], swingData[symbolIndex].Last_LL_Prices[0],
|
|
swingData[symbolIndex].Last_LL_Times[1], swingData[symbolIndex].Last_LL_Prices[0]);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, SSL_Linename, OBJPROP_TEXT, "SSL Trend");
|
|
|
|
// 3. Draw Bullish Swing High Trendline
|
|
string bullishSwingHigh_Linename = "BullishTrend_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, bullishSwingHigh_Linename, OBJ_TREND, 0,
|
|
swingData[symbolIndex].bullishSwingHighTime, swingData[symbolIndex].bullishSwingHigh,
|
|
alertTrackers[symbolIndex].bullishAlertTime, swingData[symbolIndex].bullishSwingHigh);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_COLOR, clrGreen);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_STYLE, STYLE_DASH);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, bullishSwingHigh_Linename, OBJPROP_TEXT, "Bullish Swing High");
|
|
|
|
// 4. Text Labels
|
|
string pdlTextName = "PDL_Text_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, pdlTextName, OBJ_TEXT, 0, prevDayData[symbolIndex].lowTime, prevDayData[symbolIndex].lowPrice);
|
|
ObjectSetString(chart_id, pdlTextName, OBJPROP_TEXT, "PDL");
|
|
ObjectSetInteger(chart_id, pdlTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, pdlTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, pdlTextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
string swingHighTextName = "SwingHigh_Text_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, swingHighTextName, OBJ_TEXT, 0,
|
|
swingData[symbolIndex].bullishSwingHighTime, swingData[symbolIndex].bullishSwingHigh);
|
|
ObjectSetString(chart_id, swingHighTextName, OBJPROP_TEXT, "A");
|
|
ObjectSetInteger(chart_id, swingHighTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, swingHighTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, swingHighTextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
string l2TextName = "L2_Text_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, l2TextName, OBJ_TEXT, 0,
|
|
swingData[symbolIndex].Last_LL_Times[1], swingData[symbolIndex].Last_LL_Prices[1]);
|
|
ObjectSetString(chart_id, l2TextName, OBJPROP_TEXT, "B");
|
|
ObjectSetInteger(chart_id, l2TextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, l2TextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, l2TextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
string triggerTextName = "Trigger_Text_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, triggerTextName, OBJ_TEXT, 0, timeNow, swingData[symbolIndex].bullishSwingHigh);
|
|
ObjectSetString(chart_id, triggerTextName, OBJPROP_TEXT, "C");
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
//===================================================================================
|
|
// MODIFIED RECTANGLE - Bullish (40% from B to C, time fixed)
|
|
//===================================================================================
|
|
// Calculate the move from B price to C price
|
|
double bPrice = swingData[symbolIndex].Last_LL_Prices[1];
|
|
double cPrice = swingData[symbolIndex].bullishSwingHigh; // C is the swing high (breakout level)
|
|
|
|
// For bullish: B is lower (support), C is higher (resistance)
|
|
double moveDistance = cPrice - bPrice;
|
|
|
|
// Calculate 40% level (measured FROM B upward)
|
|
double rectangleTopPrice = bPrice + (moveDistance * 0.40);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish Rectangle Calculation:");
|
|
Print("DEBUG: B Price: ", bPrice);
|
|
Print("DEBUG: C Price: ", cPrice);
|
|
Print("DEBUG: Move Distance: ", moveDistance);
|
|
Print("DEBUG: 40% Level: ", rectangleTopPrice, " (40% from B)");
|
|
Print("DEBUG: Rectangle from B (", swingData[symbolIndex].Last_LL_Prices[1], ") to ", rectangleTopPrice);
|
|
Print("DEBUG: C Time FIXED at: ", TimeToString(timeNow));
|
|
}
|
|
|
|
// Rectangle from B (bottom) to 40% level (top)
|
|
// Time coordinates are FIXED: from C time to C time + 5 periods (never changes)
|
|
string rectangleName = "Bullish_Rect_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, rectangleName, OBJ_RECTANGLE, 0,
|
|
timeNow, // Left time (C time - FIXED)
|
|
swingData[symbolIndex].Last_LL_Prices[1], // Bottom price (B)
|
|
timeNow + (5 * GetTimeframeSeconds()), // Right time (C time + 5 periods - FIXED)
|
|
rectangleTopPrice); // Top price (40% level)
|
|
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_COLOR, clrPaleGreen);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BGCOLOR, clrPaleGreen);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BACK, false);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_FILL, true);
|
|
ObjectSetDouble(chart_id, rectangleName, OBJPROP_LEVELVALUE, 0.3);
|
|
|
|
//Arrowed line - using original coordinates with FIXED time
|
|
string arrowLineName = "Bullish_Arrow_" + IntegerToString(alertTrackers[symbolIndex].bullishAlertTime);
|
|
ObjectCreate(chart_id, arrowLineName, OBJ_ARROWED_LINE, 0,
|
|
timeNow, bPrice,
|
|
timeNow + (5 * GetTimeframeSeconds()), cPrice);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_COLOR, clrBlue);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_STYLE, STYLE_DOT);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_BACK, false);
|
|
|
|
if(EnableDebugPrints) Print("DEBUG: Completed drawing bullish BREAKOUT annotations with FIXED C time: ", TimeToString(timeNow));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Draw bullish RETRACEMENT annotations (IDENTICAL code, different name) |
|
|
//+------------------------------------------------------------------+
|
|
void DrawBullishRetracementAnnotations(long chart_id, string symbol, int symbolIndex)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Drawing bullish RETRACEMENT annotations on chart ID: ", chart_id, " for ", symbol);
|
|
|
|
// USE STORED RETRACEMENT DATA
|
|
datetime timeNow = retraceTrackers[symbolIndex].bullishBreakoutTime; // Use breakout time for consistency
|
|
|
|
if(timeNow == 0)
|
|
{
|
|
Print("ERROR: Bullish retracement data not available for ", symbol);
|
|
return;
|
|
}
|
|
|
|
// 1. Draw Previous Day Low (PDL) Trendline
|
|
string PDL_Linename = "PDL_Bullish_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, PDL_Linename, OBJ_TREND, 0,
|
|
retraceTrackers[symbolIndex].bullishPrevDayLowTime, retraceTrackers[symbolIndex].bullishPrevDayLow,
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Times[0], retraceTrackers[symbolIndex].bullishPrevDayLow);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_WIDTH, 3);
|
|
ObjectSetInteger(chart_id, PDL_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, PDL_Linename, OBJPROP_TEXT, "PDL Trend");
|
|
|
|
// 2. Draw SSL (Swing Structure Low) Trendline
|
|
string SSL_Linename = "SSL_Bullish_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, SSL_Linename, OBJ_TREND, 0,
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Times[0], retraceTrackers[symbolIndex].bullishLast_LL_Prices[0],
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Times[1], retraceTrackers[symbolIndex].bullishLast_LL_Prices[0]);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, SSL_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, SSL_Linename, OBJPROP_TEXT, "SSL Trend");
|
|
|
|
// 3. Draw Bullish Swing High Trendline
|
|
string bullishSwingHigh_Linename = "BullishTrend_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, bullishSwingHigh_Linename, OBJ_TREND, 0,
|
|
retraceTrackers[symbolIndex].bullishSwingHighTime, retraceTrackers[symbolIndex].bullishSwingHigh,
|
|
timeNow, retraceTrackers[symbolIndex].bullishSwingHigh);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_COLOR, clrGreen);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_STYLE, STYLE_DASH);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(chart_id, bullishSwingHigh_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, bullishSwingHigh_Linename, OBJPROP_TEXT, "Bullish Swing High");
|
|
|
|
// 4. Text Labels
|
|
string pdlTextName = "PDL_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, pdlTextName, OBJ_TEXT, 0, retraceTrackers[symbolIndex].bullishPrevDayLowTime, retraceTrackers[symbolIndex].bullishPrevDayLow);
|
|
ObjectSetString(chart_id, pdlTextName, OBJPROP_TEXT, "PDL");
|
|
ObjectSetInteger(chart_id, pdlTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, pdlTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, pdlTextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
string swingHighTextName = "SwingHigh_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, swingHighTextName, OBJ_TEXT, 0,
|
|
retraceTrackers[symbolIndex].bullishSwingHighTime, retraceTrackers[symbolIndex].bullishSwingHigh);
|
|
ObjectSetString(chart_id, swingHighTextName, OBJPROP_TEXT, "A");
|
|
ObjectSetInteger(chart_id, swingHighTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, swingHighTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, swingHighTextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
string l2TextName = "L2_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, l2TextName, OBJ_TEXT, 0,
|
|
retraceTrackers[symbolIndex].bullishLast_LL_Times[1], retraceTrackers[symbolIndex].bullishLast_LL_Prices[1]);
|
|
ObjectSetString(chart_id, l2TextName, OBJPROP_TEXT, "B");
|
|
ObjectSetInteger(chart_id, l2TextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, l2TextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, l2TextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
string triggerTextName = "Trigger_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, triggerTextName, OBJ_TEXT, 0, timeNow, retraceTrackers[symbolIndex].bullishSwingHigh);
|
|
ObjectSetString(chart_id, triggerTextName, OBJPROP_TEXT, "C");
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
//===================================================================================
|
|
// MODIFIED RECTANGLE - Bullish (40% from B to C, time fixed)
|
|
//===================================================================================
|
|
// Calculate the move from B price to C price
|
|
double bPrice = retraceTrackers[symbolIndex].bullishLast_LL_Prices[1];
|
|
double cPrice = retraceTrackers[symbolIndex].bullishSwingHigh;
|
|
double moveDistance = cPrice - bPrice;
|
|
double rectangleTopPrice = bPrice + (moveDistance * 0.40);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bullish Retracement Rectangle Calculation:");
|
|
Print("DEBUG: B Price: ", bPrice);
|
|
Print("DEBUG: C Price: ", cPrice);
|
|
Print("DEBUG: Move Distance: ", moveDistance);
|
|
Print("DEBUG: 40% Level: ", rectangleTopPrice, " (40% from B)");
|
|
Print("DEBUG: Rectangle from B (", bPrice, ") to ", rectangleTopPrice);
|
|
Print("DEBUG: C Time FIXED at: ", TimeToString(timeNow));
|
|
}
|
|
|
|
// Rectangle from B (bottom) to 40% level (top)
|
|
string rectangleName = "Bullish_Rect_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, rectangleName, OBJ_RECTANGLE, 0,
|
|
timeNow, // Left time (C time - FIXED)
|
|
bPrice, // Bottom price (B)
|
|
timeNow + (10 * GetTimeframeSeconds()), // Right time (C time + 10 periods - FIXED)
|
|
rectangleTopPrice); // Top price (40% level)
|
|
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_COLOR, clrPaleGreen);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BGCOLOR, clrPaleGreen);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BACK, false);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_FILL, true);
|
|
ObjectSetDouble(chart_id, rectangleName, OBJPROP_LEVELVALUE, 0.3);
|
|
|
|
//Arrowed line
|
|
string arrowLineName = "Bullish_Arrow_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, arrowLineName, OBJ_ARROWED_LINE, 0,
|
|
timeNow, bPrice,
|
|
timeNow + (10 * GetTimeframeSeconds()), cPrice);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_COLOR, clrBlue);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_STYLE, STYLE_DOT);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_BACK, false);
|
|
|
|
if(EnableDebugPrints) Print("DEBUG: Completed drawing bullish RETRACEMENT annotations with FIXED C time: ", TimeToString(timeNow));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Draw bearish BREAKOUT annotations (identical to original) |
|
|
//+------------------------------------------------------------------+
|
|
void DrawBearishBreakoutAnnotations(long chart_id, string symbol, int symbolIndex)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Drawing bearish BREAKOUT annotations on chart ID: ", chart_id, " for ", symbol);
|
|
|
|
// USE STORED ALERT TIME - THIS NEVER CHANGES!
|
|
datetime timeNow = alertTrackers[symbolIndex].bearishAlertTime;
|
|
|
|
if(timeNow == 0)
|
|
{
|
|
Print("ERROR: Bearish alert time not set for ", symbol);
|
|
return;
|
|
}
|
|
|
|
// 1. Draw Previous Day High (PDH) Trendline
|
|
string PDH_Linename = "PDH_Bearish_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, PDH_Linename, OBJ_TREND, 0,
|
|
prevDayData[symbolIndex].highTime, prevDayData[symbolIndex].highPrice,
|
|
swingData[symbolIndex].Last_HH_Times[0], prevDayData[symbolIndex].highPrice);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_WIDTH, 3);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, PDH_Linename, OBJPROP_TEXT, "PDH Trend");
|
|
|
|
// 2. Draw BSL (Bearish Structure Level) Trendline
|
|
string BSL_Linename = "BSL_Bearish_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, BSL_Linename, OBJ_TREND, 0,
|
|
swingData[symbolIndex].Last_HH_Times[0], swingData[symbolIndex].Last_HH_Prices[0],
|
|
swingData[symbolIndex].Last_HH_Times[1], swingData[symbolIndex].Last_HH_Prices[0]);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, BSL_Linename, OBJPROP_TEXT, "BSL Trend");
|
|
|
|
// 3. Draw Bearish Swing Low Trendline
|
|
string bearishSwingLow_Linename = "BearishTrend_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, bearishSwingLow_Linename, OBJ_TREND, 0,
|
|
swingData[symbolIndex].bearishSwingLowTime, swingData[symbolIndex].bearishSwingLow,
|
|
alertTrackers[symbolIndex].bearishAlertTime, swingData[symbolIndex].bearishSwingLow);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_COLOR, clrRed);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_STYLE, STYLE_DASH);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, bearishSwingLow_Linename, OBJPROP_TEXT, "Bearish Swing Low");
|
|
|
|
// 4. Text Labels
|
|
string pdhTextName = "PDH_Text_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, pdhTextName, OBJ_TEXT, 0, prevDayData[symbolIndex].highTime, prevDayData[symbolIndex].highPrice);
|
|
ObjectSetString(chart_id, pdhTextName, OBJPROP_TEXT, "PDH");
|
|
ObjectSetInteger(chart_id, pdhTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, pdhTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, pdhTextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
string swingLowTextName = "SwingLow_Text_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, swingLowTextName, OBJ_TEXT, 0,
|
|
swingData[symbolIndex].bearishSwingLowTime, swingData[symbolIndex].bearishSwingLow);
|
|
ObjectSetString(chart_id, swingLowTextName, OBJPROP_TEXT, "A");
|
|
ObjectSetInteger(chart_id, swingLowTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, swingLowTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, swingLowTextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
string h2TextName = "H2_Text_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, h2TextName, OBJ_TEXT, 0,
|
|
swingData[symbolIndex].Last_HH_Times[1], swingData[symbolIndex].Last_HH_Prices[1]);
|
|
ObjectSetString(chart_id, h2TextName, OBJPROP_TEXT, "B");
|
|
ObjectSetInteger(chart_id, h2TextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, h2TextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, h2TextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
string triggerTextName = "Trigger_Text_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, triggerTextName, OBJ_TEXT, 0, timeNow, swingData[symbolIndex].bearishSwingLow);
|
|
ObjectSetString(chart_id, triggerTextName, OBJPROP_TEXT, "C");
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
//===================================================================================
|
|
// MODIFIED RECTANGLE - Bearish (40% from B to C, time fixed)
|
|
//===================================================================================
|
|
// Calculate the move from B price to C price
|
|
double bPrice = swingData[symbolIndex].Last_HH_Prices[1];
|
|
double cPrice = swingData[symbolIndex].bearishSwingLow; // C is the swing low (breakout level)
|
|
|
|
// For bearish: B is higher (resistance), C is lower (support)
|
|
double moveDistance = bPrice - cPrice;
|
|
|
|
// Calculate 40% level (measured FROM B downward)
|
|
double rectangleBottomPrice = bPrice - (moveDistance * 0.40);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish Rectangle Calculation:");
|
|
Print("DEBUG: B Price: ", bPrice);
|
|
Print("DEBUG: C Price: ", cPrice);
|
|
Print("DEBUG: Move Distance: ", moveDistance);
|
|
Print("DEBUG: 40% Level: ", rectangleBottomPrice, " (40% from B)");
|
|
Print("DEBUG: Rectangle from ", rectangleBottomPrice, " to B (", swingData[symbolIndex].Last_HH_Prices[1], ")");
|
|
Print("DEBUG: C Time FIXED at: ", TimeToString(timeNow));
|
|
}
|
|
|
|
// Rectangle from 40% level (bottom) to B (top)
|
|
string rectangleName = "Bearish_Rect_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, rectangleName, OBJ_RECTANGLE, 0,
|
|
timeNow, // Left time (C time - FIXED)
|
|
rectangleBottomPrice, // Bottom price (40% level)
|
|
timeNow + (5 * GetTimeframeSeconds()), // Right time (C time + 5 periods - FIXED)
|
|
swingData[symbolIndex].Last_HH_Prices[1]); // Top price (B)
|
|
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_COLOR, clrLightPink);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BGCOLOR, clrLightPink);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BACK, false);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_FILL, true);
|
|
ObjectSetDouble(chart_id, rectangleName, OBJPROP_LEVELVALUE, 0.3);
|
|
|
|
//Arrowed line
|
|
string arrowLineName = "Bearish_Arrow_" + IntegerToString(alertTrackers[symbolIndex].bearishAlertTime);
|
|
ObjectCreate(chart_id, arrowLineName, OBJ_ARROWED_LINE, 0,
|
|
timeNow, bPrice,
|
|
timeNow + (5 * GetTimeframeSeconds()), cPrice);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_COLOR, clrBlue);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_STYLE, STYLE_DOT);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_BACK, false);
|
|
|
|
if(EnableDebugPrints) Print("DEBUG: Completed drawing bearish BREAKOUT annotations with FIXED C time: ", TimeToString(timeNow));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Draw bearish RETRACEMENT annotations (IDENTICAL code, different name) |
|
|
//+------------------------------------------------------------------+
|
|
void DrawBearishRetracementAnnotations(long chart_id, string symbol, int symbolIndex)
|
|
{
|
|
if(EnableDebugPrints) Print("DEBUG: Drawing bearish RETRACEMENT annotations on chart ID: ", chart_id, " for ", symbol);
|
|
|
|
// USE STORED RETRACEMENT DATA
|
|
datetime timeNow = retraceTrackers[symbolIndex].bearishBreakoutTime; // Use breakout time for consistency
|
|
|
|
if(timeNow == 0)
|
|
{
|
|
Print("ERROR: Bearish retracement data not available for ", symbol);
|
|
return;
|
|
}
|
|
|
|
// 1. Draw Previous Day High (PDH) Trendline
|
|
string PDH_Linename = "PDH_Bearish_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, PDH_Linename, OBJ_TREND, 0,
|
|
retraceTrackers[symbolIndex].bearishPrevDayHighTime, retraceTrackers[symbolIndex].bearishPrevDayHigh,
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Times[0], retraceTrackers[symbolIndex].bearishPrevDayHigh);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_WIDTH, 3);
|
|
ObjectSetInteger(chart_id, PDH_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, PDH_Linename, OBJPROP_TEXT, "PDH Trend");
|
|
|
|
// 2. Draw BSL (Bearish Structure Level) Trendline
|
|
string BSL_Linename = "BSL_Bearish_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, BSL_Linename, OBJ_TREND, 0,
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Times[0], retraceTrackers[symbolIndex].bearishLast_HH_Prices[0],
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Times[1], retraceTrackers[symbolIndex].bearishLast_HH_Prices[0]);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, BSL_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, BSL_Linename, OBJPROP_TEXT, "BSL Trend");
|
|
|
|
// 3. Draw Bearish Swing Low Trendline
|
|
string bearishSwingLow_Linename = "BearishTrend_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, bearishSwingLow_Linename, OBJ_TREND, 0,
|
|
retraceTrackers[symbolIndex].bearishSwingLowTime, retraceTrackers[symbolIndex].bearishSwingLow,
|
|
timeNow, retraceTrackers[symbolIndex].bearishSwingLow);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_COLOR, clrRed);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_STYLE, STYLE_DASH);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(chart_id, bearishSwingLow_Linename, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetString(chart_id, bearishSwingLow_Linename, OBJPROP_TEXT, "Bearish Swing Low");
|
|
|
|
// 4. Text Labels
|
|
string pdhTextName = "PDH_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, pdhTextName, OBJ_TEXT, 0, retraceTrackers[symbolIndex].bearishPrevDayHighTime, retraceTrackers[symbolIndex].bearishPrevDayHigh);
|
|
ObjectSetString(chart_id, pdhTextName, OBJPROP_TEXT, "PDH");
|
|
ObjectSetInteger(chart_id, pdhTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, pdhTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, pdhTextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
string swingLowTextName = "SwingLow_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, swingLowTextName, OBJ_TEXT, 0,
|
|
retraceTrackers[symbolIndex].bearishSwingLowTime, retraceTrackers[symbolIndex].bearishSwingLow);
|
|
ObjectSetString(chart_id, swingLowTextName, OBJPROP_TEXT, "A");
|
|
ObjectSetInteger(chart_id, swingLowTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, swingLowTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, swingLowTextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
string h2TextName = "H2_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, h2TextName, OBJ_TEXT, 0,
|
|
retraceTrackers[symbolIndex].bearishLast_HH_Times[1], retraceTrackers[symbolIndex].bearishLast_HH_Prices[1]);
|
|
ObjectSetString(chart_id, h2TextName, OBJPROP_TEXT, "B");
|
|
ObjectSetInteger(chart_id, h2TextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, h2TextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, h2TextName, OBJPROP_ANCHOR, ANCHOR_LOWER);
|
|
|
|
string triggerTextName = "Trigger_Text_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, triggerTextName, OBJ_TEXT, 0, timeNow, retraceTrackers[symbolIndex].bearishSwingLow);
|
|
ObjectSetString(chart_id, triggerTextName, OBJPROP_TEXT, "C");
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_COLOR, clrBlack);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(chart_id, triggerTextName, OBJPROP_ANCHOR, ANCHOR_UPPER);
|
|
|
|
//===================================================================================
|
|
// MODIFIED RECTANGLE - Bearish (40% from B to C, time fixed)
|
|
//===================================================================================
|
|
// Calculate the move from B price to C price
|
|
double bPrice = retraceTrackers[symbolIndex].bearishLast_HH_Prices[1];
|
|
double cPrice = retraceTrackers[symbolIndex].bearishSwingLow;
|
|
double moveDistance = bPrice - cPrice;
|
|
double rectangleBottomPrice = bPrice - (moveDistance * 0.40);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Bearish Retracement Rectangle Calculation:");
|
|
Print("DEBUG: B Price: ", bPrice);
|
|
Print("DEBUG: C Price: ", cPrice);
|
|
Print("DEBUG: Move Distance: ", moveDistance);
|
|
Print("DEBUG: 40% Level: ", rectangleBottomPrice, " (40% from B)");
|
|
Print("DEBUG: Rectangle from ", rectangleBottomPrice, " to B (", bPrice, ")");
|
|
Print("DEBUG: C Time FIXED at: ", TimeToString(timeNow));
|
|
}
|
|
|
|
// Rectangle from 40% level (bottom) to B (top)
|
|
string rectangleName = "Bearish_Rect_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, rectangleName, OBJ_RECTANGLE, 0,
|
|
timeNow, // Left time (C time - FIXED)
|
|
rectangleBottomPrice, // Bottom price (40% level)
|
|
timeNow + (10 * GetTimeframeSeconds()), // Right time (C time + 10 periods - FIXED)
|
|
bPrice); // Top price (B)
|
|
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_COLOR, clrLightPink);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BGCOLOR, clrLightPink);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_BACK, false);
|
|
ObjectSetInteger(chart_id, rectangleName, OBJPROP_FILL, true);
|
|
ObjectSetDouble(chart_id, rectangleName, OBJPROP_LEVELVALUE, 0.3);
|
|
|
|
//Arrowed line
|
|
string arrowLineName = "Bearish_Arrow_Retrace_" + IntegerToString(timeNow);
|
|
ObjectCreate(chart_id, arrowLineName, OBJ_ARROWED_LINE, 0,
|
|
timeNow, bPrice,
|
|
timeNow + (10 * GetTimeframeSeconds()), cPrice);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_COLOR, clrBlue);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_RAY_RIGHT, false);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_STYLE, STYLE_DOT);
|
|
ObjectSetInteger(chart_id, arrowLineName, OBJPROP_BACK, false);
|
|
|
|
if(EnableDebugPrints) Print("DEBUG: Completed drawing bearish RETRACEMENT annotations with FIXED C time: ", TimeToString(timeNow));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Take screenshot |
|
|
//+------------------------------------------------------------------+
|
|
string TakeScreenshot(string alertType, string symbol, int symbolIndex)
|
|
{
|
|
string filename = alertType + "_" + symbol + "_" + IntegerToString(TimeCurrent()) + ".png";
|
|
|
|
long chart_id = 0;
|
|
/*
|
|
ChartOpen(symbol, _Period);
|
|
if(chart_id <= 0)
|
|
{
|
|
Print("ERROR: Failed to open chart for ", symbol);
|
|
return "";
|
|
}
|
|
*/
|
|
|
|
Sleep(500);
|
|
tradeviewtpl(chart_id);
|
|
Sleep(200);
|
|
|
|
// Call the appropriate annotation function based on alert type
|
|
if(alertType == "Bullish_Breakout")
|
|
{
|
|
DrawBullishBreakoutAnnotations(chart_id, symbol, symbolIndex);
|
|
}
|
|
else if(alertType == "Bullish_Retracement")
|
|
{
|
|
DrawBullishRetracementAnnotations(chart_id, symbol, symbolIndex);
|
|
}
|
|
else if(alertType == "Bearish_Breakout")
|
|
{
|
|
DrawBearishBreakoutAnnotations(chart_id, symbol, symbolIndex);
|
|
}
|
|
else if(alertType == "Bearish_Retracement")
|
|
{
|
|
DrawBearishRetracementAnnotations(chart_id, symbol, symbolIndex);
|
|
}
|
|
|
|
DrawWatermark(chart_id);
|
|
Sleep(300);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Attempting to capture screenshot for ", alertType, " alert on chart ID: ", chart_id);
|
|
Print("DEBUG: Screenshot filename: ", filename);
|
|
}
|
|
|
|
if(ChartScreenShot(chart_id, filename, 1350, 1080, ALIGN_RIGHT))
|
|
{
|
|
if(CloseChartAfterScreenshot)
|
|
{
|
|
ChartClose(chart_id);
|
|
}
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Screenshot captured successfully: ", filename);
|
|
Print("DEBUG: Saved to: ", TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\" + filename);
|
|
if(CloseChartAfterScreenshot) Print("DEBUG: Temporary chart closed");
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
else
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: ERROR - Screenshot capture failed. Last error: ", GetLastError());
|
|
}
|
|
ChartClose(chart_id);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Draw watermark |
|
|
//+------------------------------------------------------------------+
|
|
string WM_NAME = "TV_STYLE_WATERMARK";
|
|
bool DrawWatermark(long chartid)
|
|
{
|
|
string tf = GetTimeframeString();
|
|
string symbol = ChartSymbol(chartid);
|
|
string text = symbol + " " + tf;
|
|
|
|
if(ObjectFind(chartid, WM_NAME) == -1)
|
|
{
|
|
ObjectCreate(chartid, WM_NAME, OBJ_LABEL, 0, 0, 0);
|
|
ObjectSetString(chartid, WM_NAME, OBJPROP_TEXT, text);
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_COLOR, clrSilver);
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_FONTSIZE, 50);
|
|
ObjectSetString(chartid, WM_NAME, OBJPROP_FONT, "Arial Black");
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_BACK, true);
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_HIDDEN, true);
|
|
|
|
// Calculate center position
|
|
int center_x = 1350 / 2;
|
|
int center_y = 1080 / 2;
|
|
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_XDISTANCE, center_x);
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_YDISTANCE, center_y);
|
|
ObjectSetInteger(chartid, WM_NAME, OBJPROP_ANCHOR, ANCHOR_CENTER);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Apply TradingView style template |
|
|
//+------------------------------------------------------------------+
|
|
void tradeviewtpl(long chartid)
|
|
{
|
|
ChartSetInteger(chartid, CHART_COLOR_BACKGROUND, C'242,242,242');
|
|
ChartSetInteger(chartid, CHART_COLOR_FOREGROUND, C'19,23,34');
|
|
ChartSetInteger(chartid, CHART_COLOR_GRID, clrNONE);
|
|
ChartSetInteger(chartid, CHART_COLOR_CHART_UP, C'38,166,154');
|
|
ChartSetInteger(chartid, CHART_COLOR_CHART_DOWN, C'239,83,80');
|
|
ChartSetInteger(chartid, CHART_COLOR_CANDLE_BULL, C'38,166,154');
|
|
ChartSetInteger(chartid, CHART_COLOR_CANDLE_BEAR, C'239,83,80');
|
|
ChartSetInteger(chartid, CHART_COLOR_CHART_LINE, C'38,166,154');
|
|
ChartSetInteger(chartid, CHART_SHOW_VOLUMES, false);
|
|
ChartSetInteger(chartid, CHART_SHIFT, true);
|
|
ChartSetInteger(chartid, CHART_SCALE, 3);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Send alert data to server |
|
|
//+------------------------------------------------------------------+
|
|
void SendAlertData(string alertType, double priceLevel, datetime swingTime, datetime alertTime,
|
|
string screenshotFilename, string uniqueId, string symbol, int symbolIndex)
|
|
{
|
|
//Ensures screenshot if fully saved
|
|
Sleep(5000);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Preparing to send alert data to API for ", symbol);
|
|
Print("DEBUG: Alert Type: ", alertType);
|
|
Print("DEBUG: Price Level: ", priceLevel);
|
|
Print("DEBUG: Swing Time: ", TimeToString(swingTime));
|
|
Print("DEBUG: Alert Time: ", TimeToString(alertTime));
|
|
Print("DEBUG: Unique ID: ", uniqueId);
|
|
}
|
|
|
|
string symbolSector = GetCustomSector(symbol);
|
|
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
|
|
string jsonPayload = "{";
|
|
jsonPayload += "\"symbol\":\"" + symbol + "\",";
|
|
jsonPayload += "\"sector\":\"" + symbolSector + "\",";
|
|
jsonPayload += "\"timeframe\":\"" + GetTimeframeString() + "\",";
|
|
jsonPayload += "\"alert_type\":\"" + alertType + "\",";
|
|
jsonPayload += "\"price_level\":" + DoubleToString(priceLevel, digits) + ",";
|
|
jsonPayload += "\"swing_time\":" + IntegerToString(swingTime) + ",";
|
|
jsonPayload += "\"alert_time\":" + IntegerToString(alertTime) + ",";
|
|
jsonPayload += "\"bias\":\"" + BiasEnumToString(biasData[symbolIndex].bias) + "\",";
|
|
jsonPayload += "\"session\":\"" + currentSession + "\",";
|
|
jsonPayload += "\"strategy_name\":\"" + strategyName + "\",";
|
|
jsonPayload += "\"strategy_id\":\"" + strategyId + "\",";
|
|
jsonPayload += "\"unique_id\":\"" + uniqueId + "\",";
|
|
jsonPayload += "\"screenshot_filename\":\"" + screenshotFilename + "\",";
|
|
jsonPayload += "\"allowed_timeframes\":[";
|
|
|
|
int tfCount = ArraySize(allowedTimeframe);
|
|
for(int i = 0; i < tfCount; i++)
|
|
{
|
|
jsonPayload += "\"" + allowedTimeframe[i] + "\"";
|
|
if(i < tfCount - 1)
|
|
jsonPayload += ",";
|
|
}
|
|
jsonPayload += "],";
|
|
|
|
jsonPayload += "\"current_bid\":" + DoubleToString(swingData[symbolIndex].currentBidPrice, digits) + ",";
|
|
jsonPayload += "\"current_ask\":" + DoubleToString(swingData[symbolIndex].currentAskPrice, digits);
|
|
jsonPayload += "}";
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: JSON Payload:");
|
|
Print(jsonPayload);
|
|
}
|
|
|
|
string headers = "Content-Type: application/json\r\n";
|
|
|
|
uchar dataArray[];
|
|
StringToCharArray(jsonPayload, dataArray, 0, StringLen(jsonPayload));
|
|
|
|
uchar result[];
|
|
string resultHeaders;
|
|
int response = WebRequest("POST", alertServerURL, headers, 10000, dataArray, result, resultHeaders);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Alert data sent. Response: ", response);
|
|
if(response == 200)
|
|
{
|
|
Print("DEBUG: SUCCESS - Alert data sent | Unique ID: ", uniqueId);
|
|
}
|
|
else if(response == -1)
|
|
{
|
|
Print("DEBUG: ERROR - WebRequest failed. Error: ", GetLastError());
|
|
}
|
|
else
|
|
{
|
|
Print("DEBUG: Server response: ", response);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Convert bias enum to string |
|
|
//+------------------------------------------------------------------+
|
|
string BiasEnumToString(ENUM_BIAS bias)
|
|
{
|
|
switch(bias)
|
|
{
|
|
case BIAS_NEUTRAL: return "NEUTRAL";
|
|
case BIAS_BULLISH: return "BULLISH";
|
|
case BIAS_BEARISH: return "BEARISH";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Send screenshot binary data |
|
|
//+------------------------------------------------------------------+
|
|
void SendScreenshotBinary(string filename, string alertType, string uniqueId, string symbol, int symbolIndex)
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Preparing to send screenshot for ", symbol);
|
|
Print("DEBUG: File: ", filename);
|
|
Print("DEBUG: Unique ID: ", uniqueId);
|
|
}
|
|
|
|
int filehandle = FileOpen(filename, FILE_READ | FILE_BIN);
|
|
if(filehandle == INVALID_HANDLE)
|
|
{
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: ERROR - Could not open file: ", filename);
|
|
Print("DEBUG: Last error: ", GetLastError());
|
|
}
|
|
return;
|
|
}
|
|
|
|
int fileSize = (int)FileSize(filehandle);
|
|
|
|
uchar byteArray[];
|
|
ArrayResize(byteArray, fileSize);
|
|
FileReadArray(filehandle, byteArray, 0, fileSize);
|
|
FileClose(filehandle);
|
|
|
|
string boundary = "----WebKitFormBoundary" + IntegerToString(TimeCurrent());
|
|
string headers = "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n";
|
|
|
|
string formData = "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"alert_type\"\r\n\r\n";
|
|
formData += alertType + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"symbol\"\r\n\r\n";
|
|
formData += symbol + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"timestamp\"\r\n\r\n";
|
|
formData += IntegerToString(TimeCurrent()) + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"strategy_name\"\r\n\r\n";
|
|
formData += strategyName + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"strategy_id\"\r\n\r\n";
|
|
formData += strategyId + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"sector\"\r\n\r\n";
|
|
formData += GetCustomSector(symbol) + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"timeframe\"\r\n\r\n";
|
|
formData += GetTimeframeString() + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"session\"\r\n\r\n";
|
|
formData += currentSession + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"bias\"\r\n\r\n";
|
|
formData += BiasEnumToString(biasData[symbolIndex].bias) + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"unique_id\"\r\n\r\n";
|
|
formData += uniqueId + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"screenshot_filename\"\r\n\r\n";
|
|
formData += filename + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"allowed_timeframes\"\r\n\r\n";
|
|
string allowedTFsStr = "";
|
|
int tfCount = ArraySize(allowedTimeframe);
|
|
for(int i = 0; i < tfCount; i++)
|
|
{
|
|
allowedTFsStr += allowedTimeframe[i];
|
|
if(i < tfCount - 1)
|
|
allowedTFsStr += ",";
|
|
}
|
|
formData += allowedTFsStr + "\r\n";
|
|
|
|
formData += "--" + boundary + "\r\n";
|
|
formData += "Content-Disposition: form-data; name=\"screenshot\"; filename=\"" + filename + "\"\r\n";
|
|
formData += "Content-Type: image/png\r\n\r\n";
|
|
|
|
uchar headerArray[];
|
|
StringToCharArray(formData, headerArray, 0, StringLen(formData));
|
|
|
|
string footer = "\r\n--" + boundary + "--\r\n";
|
|
uchar footerArray[];
|
|
StringToCharArray(footer, footerArray, 0, StringLen(footer));
|
|
|
|
uchar postData[];
|
|
int totalSize = ArraySize(headerArray) + ArraySize(byteArray) + ArraySize(footerArray);
|
|
ArrayResize(postData, totalSize);
|
|
|
|
for(int i = 0; i < ArraySize(headerArray); i++)
|
|
postData[i] = headerArray[i];
|
|
|
|
int offset = ArraySize(headerArray);
|
|
for(int i = 0; i < ArraySize(byteArray); i++)
|
|
postData[offset + i] = byteArray[i];
|
|
|
|
offset += ArraySize(byteArray);
|
|
for(int i = 0; i < ArraySize(footerArray); i++)
|
|
postData[offset + i] = footerArray[i];
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Sending multipart data, size: ", totalSize, " bytes");
|
|
}
|
|
|
|
uchar result[];
|
|
string resultHeaders;
|
|
int response = WebRequest("POST", screenshotServerURL, headers, 15000, postData, result, resultHeaders);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Screenshot sent. Response: ", response);
|
|
if(response == 200)
|
|
{
|
|
Print("DEBUG: SUCCESS - Screenshot sent | Unique ID: ", uniqueId);
|
|
}
|
|
else if(response == 400)
|
|
{
|
|
Print("DEBUG: ERROR - Bad Request (400)");
|
|
}
|
|
else if(response == -1)
|
|
{
|
|
Print("DEBUG: ERROR - WebRequest failed. Error: ", GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// SWING ANALYSIS FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Find swing points |
|
|
//+------------------------------------------------------------------+
|
|
void FindSwingPoints(int symbolIndex)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
int symbol_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
|
|
int startBar = SwingLookbackBars + SwingLeftBars;
|
|
|
|
for(int i = startBar; i >= SwingRightBars; i--)
|
|
{
|
|
double currentLow = iLow(symbol, PERIOD_CURRENT, i);
|
|
double currentHigh = iHigh(symbol, PERIOD_CURRENT, i);
|
|
|
|
bool isSwingLow = true;
|
|
bool isSwingHigh = true;
|
|
|
|
// Check swing low left side
|
|
for(int left = 1; left <= SwingLeftBars; left++)
|
|
{
|
|
double leftLow = iLow(symbol, PERIOD_CURRENT, i + left);
|
|
if(currentLow >= leftLow)
|
|
{
|
|
isSwingLow = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check swing low right side
|
|
if(isSwingLow)
|
|
{
|
|
for(int right = 1; right <= SwingRightBars; right++)
|
|
{
|
|
double rightLow = iLow(symbol, PERIOD_CURRENT, i - right);
|
|
if(currentLow >= rightLow)
|
|
{
|
|
isSwingLow = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check swing high left side
|
|
for(int left = 1; left <= SwingLeftBars; left++)
|
|
{
|
|
double leftHigh = iHigh(symbol, PERIOD_CURRENT, i + left);
|
|
if(currentHigh <= leftHigh)
|
|
{
|
|
isSwingHigh = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check swing high right side
|
|
if(isSwingHigh)
|
|
{
|
|
for(int right = 1; right <= SwingRightBars; right++)
|
|
{
|
|
double rightHigh = iHigh(symbol, PERIOD_CURRENT, i - right);
|
|
if(currentHigh <= rightHigh)
|
|
{
|
|
isSwingHigh = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add swing low
|
|
if(isSwingLow)
|
|
{
|
|
double swingLowPrice = NormalizeDouble(currentLow, symbol_digits);
|
|
datetime swingLowTime = iTime(symbol, PERIOD_CURRENT, i);
|
|
|
|
int size = ArraySize(swingData[symbolIndex].swingLowPrices);
|
|
ArrayResize(swingData[symbolIndex].swingLowPrices, size + 1);
|
|
ArrayResize(swingData[symbolIndex].swingLowTimes, size + 1);
|
|
|
|
swingData[symbolIndex].swingLowPrices[size] = swingLowPrice;
|
|
swingData[symbolIndex].swingLowTimes[size] = swingLowTime;
|
|
}
|
|
|
|
// Add swing high
|
|
if(isSwingHigh)
|
|
{
|
|
double swingHighPrice = NormalizeDouble(currentHigh, symbol_digits);
|
|
datetime swingHighTime = iTime(symbol, PERIOD_CURRENT, i);
|
|
|
|
int size = ArraySize(swingData[symbolIndex].swingHighPrices);
|
|
ArrayResize(swingData[symbolIndex].swingHighPrices, size + 1);
|
|
ArrayResize(swingData[symbolIndex].swingHighTimes, size + 1);
|
|
|
|
swingData[symbolIndex].swingHighPrices[size] = swingHighPrice;
|
|
swingData[symbolIndex].swingHighTimes[size] = swingHighTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get consecutive highs and lows |
|
|
//+------------------------------------------------------------------+
|
|
void GetConsecutiveHighsAndLows(int symbolIndex)
|
|
{
|
|
ArrayInitialize(swingData[symbolIndex].HH_Prices, 0);
|
|
ArrayInitialize(swingData[symbolIndex].HH_Times, 0);
|
|
ArrayInitialize(swingData[symbolIndex].LL_Prices, 0);
|
|
ArrayInitialize(swingData[symbolIndex].LL_Times, 0);
|
|
|
|
int swingHighCount = ArraySize(swingData[symbolIndex].swingHighPrices);
|
|
int swingLowCount = ArraySize(swingData[symbolIndex].swingLowPrices);
|
|
|
|
// Find last 2 consecutive higher highs
|
|
for(int i = swingHighCount - 1; i >= 1; i--)
|
|
{
|
|
if(swingData[symbolIndex].swingHighPrices[i] > swingData[symbolIndex].swingHighPrices[i - 1])
|
|
{
|
|
swingData[symbolIndex].HH_Prices[1] = swingData[symbolIndex].swingHighPrices[i];
|
|
swingData[symbolIndex].HH_Times[1] = swingData[symbolIndex].swingHighTimes[i];
|
|
swingData[symbolIndex].HH_Prices[0] = swingData[symbolIndex].swingHighPrices[i - 1];
|
|
swingData[symbolIndex].HH_Times[0] = swingData[symbolIndex].swingHighTimes[i - 1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find last 2 consecutive lower lows
|
|
for(int i = swingLowCount - 1; i >= 1; i--)
|
|
{
|
|
if(swingData[symbolIndex].swingLowPrices[i] < swingData[symbolIndex].swingLowPrices[i - 1])
|
|
{
|
|
swingData[symbolIndex].LL_Prices[1] = swingData[symbolIndex].swingLowPrices[i];
|
|
swingData[symbolIndex].LL_Times[1] = swingData[symbolIndex].swingLowTimes[i];
|
|
swingData[symbolIndex].LL_Prices[0] = swingData[symbolIndex].swingLowPrices[i - 1];
|
|
swingData[symbolIndex].LL_Times[0] = swingData[symbolIndex].swingLowTimes[i - 1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Determine breakout points |
|
|
//+------------------------------------------------------------------+
|
|
void GetBreakPoint(int symbolIndex)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
if(biasData[symbolIndex].bias == BIAS_BULLISH)
|
|
{
|
|
int Bullish_BarsInBetween = GetBarsBetweenTimes(swingData[symbolIndex].LL_Times[0],
|
|
swingData[symbolIndex].LL_Times[1], symbol);
|
|
int L2_Index = iBarShift(symbol, PERIOD_CURRENT, swingData[symbolIndex].LL_Times[1], true);
|
|
|
|
int highestHigh_Index = iHighest(symbol, PERIOD_CURRENT, MODE_HIGH,
|
|
Bullish_BarsInBetween - 1, L2_Index + 1);
|
|
|
|
if(Is3BarSwingHigh(highestHigh_Index, symbol))
|
|
{
|
|
swingData[symbolIndex].bullishSwingHigh = iHigh(symbol, PERIOD_CURRENT, highestHigh_Index);
|
|
swingData[symbolIndex].bullishSwingHighTime = iTime(symbol, PERIOD_M15, highestHigh_Index);
|
|
|
|
swingData[symbolIndex].Last_LL_Times[0] = swingData[symbolIndex].LL_Times[0];
|
|
swingData[symbolIndex].Last_LL_Times[1] = swingData[symbolIndex].LL_Times[1];
|
|
swingData[symbolIndex].Last_LL_Prices[0] = swingData[symbolIndex].LL_Prices[0];
|
|
swingData[symbolIndex].Last_LL_Prices[1] = swingData[symbolIndex].LL_Prices[1];
|
|
}
|
|
}
|
|
else if(biasData[symbolIndex].bias == BIAS_BEARISH)
|
|
{
|
|
int Bearish_BarsInBetween = GetBarsBetweenTimes(swingData[symbolIndex].HH_Times[0],
|
|
swingData[symbolIndex].HH_Times[1], symbol);
|
|
int H2_Index = iBarShift(symbol, PERIOD_CURRENT, swingData[symbolIndex].HH_Times[1], true);
|
|
|
|
int lowestLow_Index = iLowest(symbol, PERIOD_CURRENT, MODE_LOW,
|
|
Bearish_BarsInBetween - 1, H2_Index + 1);
|
|
|
|
if(Is3BarSwingLow(lowestLow_Index, symbol))
|
|
{
|
|
swingData[symbolIndex].bearishSwingLow = iLow(symbol, PERIOD_CURRENT, lowestLow_Index);
|
|
swingData[symbolIndex].bearishSwingLowTime = iTime(symbol, PERIOD_M15, lowestLow_Index);
|
|
|
|
swingData[symbolIndex].Last_HH_Times[0] = swingData[symbolIndex].HH_Times[0];
|
|
swingData[symbolIndex].Last_HH_Times[1] = swingData[symbolIndex].HH_Times[1];
|
|
swingData[symbolIndex].Last_HH_Prices[0] = swingData[symbolIndex].HH_Prices[0];
|
|
swingData[symbolIndex].Last_HH_Prices[1] = swingData[symbolIndex].HH_Prices[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// SWING PATTERN VALIDATION FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if 3-bar swing low |
|
|
//+------------------------------------------------------------------+
|
|
bool Is3BarSwingLow(int swingLowBarIndex, string symbol)
|
|
{
|
|
if(swingLowBarIndex < 1) return false;
|
|
|
|
return (iLow(symbol, PERIOD_CURRENT, swingLowBarIndex) < iLow(symbol, PERIOD_CURRENT, swingLowBarIndex + 1) &&
|
|
iLow(symbol, PERIOD_CURRENT, swingLowBarIndex) < iLow(symbol, PERIOD_CURRENT, swingLowBarIndex - 1));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if 3-bar swing high |
|
|
//+------------------------------------------------------------------+
|
|
bool Is3BarSwingHigh(int swingHighBarIndex, string symbol)
|
|
{
|
|
if(swingHighBarIndex < 1) return false;
|
|
|
|
return (iHigh(symbol, PERIOD_CURRENT, swingHighBarIndex) > iHigh(symbol, PERIOD_CURRENT, swingHighBarIndex + 1) &&
|
|
iHigh(symbol, PERIOD_CURRENT, swingHighBarIndex) > iHigh(symbol, PERIOD_CURRENT, swingHighBarIndex - 1));
|
|
}
|
|
|
|
// ============================================================
|
|
// TIME AND BAR CALCULATION FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate bars between times |
|
|
//+------------------------------------------------------------------+
|
|
int GetBarsBetweenTimes(datetime startTime, datetime endTime, string symbol)
|
|
{
|
|
if(startTime > endTime)
|
|
{
|
|
datetime temp = startTime;
|
|
startTime = endTime;
|
|
endTime = temp;
|
|
}
|
|
|
|
int startBar = iBarShift(symbol, PERIOD_CURRENT, startTime, true);
|
|
int endBar = iBarShift(symbol, PERIOD_CURRENT, endTime, true);
|
|
|
|
if(startBar != -1 && endBar != -1)
|
|
{
|
|
return MathAbs(startBar - endBar);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Determine market bias |
|
|
//+------------------------------------------------------------------+
|
|
void FindBias(int symbolIndex)
|
|
{
|
|
string symbol = Symbols[symbolIndex];
|
|
|
|
double dailyHigh0 = iHigh(symbol, PERIOD_D1, 0);
|
|
double dailyHigh1 = prevDayData[symbolIndex].highPrice;
|
|
double dailyLow0 = iLow(symbol, PERIOD_D1, 0);
|
|
double dailyLow1 = prevDayData[symbolIndex].lowPrice;
|
|
|
|
if(dailyHigh0 > dailyHigh1)
|
|
{
|
|
biasData[symbolIndex].bias = BIAS_BEARISH;
|
|
}
|
|
|
|
if(dailyLow0 < dailyLow1)
|
|
{
|
|
biasData[symbolIndex].bias = BIAS_BULLISH;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for new day |
|
|
//+------------------------------------------------------------------+
|
|
bool IsNewDay(int index)
|
|
{
|
|
datetime t = iTime(Symbols[index], PERIOD_D1, 0);
|
|
if(t != last_bar_time_d[index])
|
|
{
|
|
last_bar_time_d[index] = t;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for new 15-min bar |
|
|
//+------------------------------------------------------------------+
|
|
bool IsNew15MinBar(int index)
|
|
{
|
|
datetime t = iTime(Symbols[index], PERIOD_M15, 0);
|
|
if(t != last_bar_time[index])
|
|
{
|
|
last_bar_time[index] = t;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ============================================================
|
|
// PREVIOUS DAY ANALYSIS FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get last tradeable day start |
|
|
//+------------------------------------------------------------------+
|
|
datetime GetLastTradeableDayStart(string symbol)
|
|
{
|
|
int maxDaysToCheck = 10;
|
|
datetime currentTime = TimeCurrent();
|
|
|
|
for(int daysBack = 1; daysBack <= maxDaysToCheck; daysBack++)
|
|
{
|
|
datetime dayToCheck = currentTime - (daysBack * 86400);
|
|
|
|
MqlDateTime dt;
|
|
TimeToStruct(dayToCheck, dt);
|
|
dt.hour = 0;
|
|
dt.min = 0;
|
|
dt.sec = 0;
|
|
dayToCheck = StructToTime(dt);
|
|
|
|
datetime nextDay = dayToCheck + 86400;
|
|
|
|
MqlRates rates[];
|
|
int copied = CopyRates(symbol, PERIOD_M15, dayToCheck, nextDay, rates);
|
|
|
|
if(copied >= MinCandlesForTradeableDay)
|
|
{
|
|
return dayToCheck;
|
|
}
|
|
}
|
|
|
|
datetime yesterday = currentTime - 86400;
|
|
MqlDateTime dtYest;
|
|
TimeToStruct(yesterday, dtYest);
|
|
dtYest.hour = 0;
|
|
dtYest.min = 0;
|
|
dtYest.sec = 0;
|
|
yesterday = StructToTime(dtYest);
|
|
|
|
if(EnableDebugPrints)
|
|
{
|
|
Print("DEBUG: Using fallback - yesterday: ", TimeToString(yesterday, TIME_DATE));
|
|
}
|
|
return yesterday;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get previous day high time |
|
|
//+------------------------------------------------------------------+
|
|
datetime GetM15PrevDayHighTime(string symbol)
|
|
{
|
|
MqlRates rates[];
|
|
datetime highTime = 0;
|
|
double highest = 0;
|
|
|
|
datetime prevTradeableDay = GetLastTradeableDayStart(symbol);
|
|
datetime currentDayOpen = iTime(symbol, PERIOD_D1, 0);
|
|
|
|
int copied = CopyRates(symbol, PERIOD_M15, prevTradeableDay, currentDayOpen, rates);
|
|
|
|
if(copied <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for(int i = 0; i < copied; i++)
|
|
{
|
|
if(rates[i].high > highest)
|
|
{
|
|
highest = rates[i].high;
|
|
highTime = rates[i].time;
|
|
}
|
|
}
|
|
|
|
return highTime;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get previous day low time |
|
|
//+------------------------------------------------------------------+
|
|
datetime GetM15PrevDayLowTime(string symbol)
|
|
{
|
|
MqlRates rates[];
|
|
datetime lowTime = 0;
|
|
double lowest = DBL_MAX;
|
|
|
|
datetime prevTradeableDay = GetLastTradeableDayStart(symbol);
|
|
datetime currentDayOpen = iTime(symbol, PERIOD_D1, 0);
|
|
|
|
int copied = CopyRates(symbol, PERIOD_M15, prevTradeableDay, currentDayOpen, rates);
|
|
|
|
if(copied <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for(int i = 0; i < copied; i++)
|
|
{
|
|
if(rates[i].low < lowest)
|
|
{
|
|
lowest = rates[i].low;
|
|
lowTime = rates[i].time;
|
|
}
|
|
}
|
|
|
|
return lowTime;
|
|
}
|
|
|
|
// ============================================================
|
|
// SESSION MANAGEMENT FUNCTIONS
|
|
// ============================================================
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if in session |
|
|
//+------------------------------------------------------------------+
|
|
bool IsInSession(string sessionStart, string sessionEnd)
|
|
{
|
|
datetime currentTime = TimeCurrent();
|
|
MqlDateTime timeStruct;
|
|
TimeToStruct(currentTime, timeStruct);
|
|
|
|
string startTimeStr = TimeToString(currentTime, TIME_DATE) + " " + sessionStart;
|
|
string endTimeStr = TimeToString(currentTime, TIME_DATE) + " " + sessionEnd;
|
|
|
|
datetime sessionStartTime = StringToTime(startTimeStr);
|
|
datetime sessionEndTime = StringToTime(endTimeStr);
|
|
|
|
if(sessionEndTime <= sessionStartTime)
|
|
{
|
|
sessionEndTime += 24 * 60 * 60;
|
|
}
|
|
|
|
return (currentTime >= sessionStartTime && currentTime < sessionEndTime);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get current session |
|
|
//+------------------------------------------------------------------+
|
|
string GetCurrentSession()
|
|
{
|
|
if(IsInSession(SydneySessionStart, SydneySessionEnd))
|
|
return "Sydney";
|
|
if(IsInSession(AsiaSessionStart, AsiaSessionEnd))
|
|
return "Asian";
|
|
else if(IsInSession(LondonSessionStart, LondonSessionEnd))
|
|
return "London";
|
|
else if(IsInSession(NewYorkSessionStart, NewYorkSessionEnd))
|
|
return "NewYork";
|
|
else
|
|
return "OutsideSession";
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get timeframe string |
|
|
//+------------------------------------------------------------------+
|
|
string GetTimeframeString()
|
|
{
|
|
switch(_Period)
|
|
{
|
|
case PERIOD_M1: return "M1";
|
|
case PERIOD_M5: return "M5";
|
|
case PERIOD_M15: return "M15";
|
|
case PERIOD_M30: return "M30";
|
|
case PERIOD_H1: return "H1";
|
|
case PERIOD_H4: return "H4";
|
|
case PERIOD_H12: return "H12";
|
|
case PERIOD_D1: return "D1";
|
|
case PERIOD_W1: return "W1";
|
|
case PERIOD_MN1: return "MN1";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get timeframe seconds |
|
|
//+------------------------------------------------------------------+
|
|
int GetTimeframeSeconds()
|
|
{
|
|
switch(_Period)
|
|
{
|
|
case PERIOD_M1: return 60;
|
|
case PERIOD_M2: return 120;
|
|
case PERIOD_M3: return 180;
|
|
case PERIOD_M4: return 240;
|
|
case PERIOD_M5: return 300;
|
|
case PERIOD_M6: return 360;
|
|
case PERIOD_M10: return 600;
|
|
case PERIOD_M12: return 720;
|
|
case PERIOD_M15: return 900;
|
|
case PERIOD_M20: return 1200;
|
|
case PERIOD_M30: return 1800;
|
|
case PERIOD_H1: return 3600;
|
|
case PERIOD_H2: return 7200;
|
|
case PERIOD_H3: return 10800;
|
|
case PERIOD_H4: return 14400;
|
|
case PERIOD_H6: return 21600;
|
|
case PERIOD_H8: return 28800;
|
|
case PERIOD_H12: return 43200;
|
|
case PERIOD_D1: return 86400;
|
|
case PERIOD_W1: return 604800;
|
|
default: return 3600;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+ |