TDi_momentum/TDI_Momentum_Pulse.mq5

308 lines
12 KiB
MQL5
Raw Permalink Normal View History

2025-12-16 15:17:18 +00:00
//+------------------------------------------------------------------+
//| TDI_Momentum_Pulse.mq5 |
//| Generated by Ruben Works |
//| Based on Master Trading Plan v1 |
//+------------------------------------------------------------------+
#property copyright "Ruben Works"
#property link ""
#property version "1.00"
// Include Standard Libraries
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
//--- Input Parameters
input group "Strategy Settings"
input double InpLots = 0.02; // Lot Size (Reduced for 750 pip risk)
input int InpStopLoss = 7500; // Stop Loss (Points, 750 Pips - Safe Mode)
input int InpTakeProfit = 3000; // Take Profit (Points, 300 Pips)
input int InpMagic = 123456; // Magic Number
input int InpTimeExitHours = 16; // Max Holding Time (Hours)
input group "Trailing Stop Settings"
input bool InpUseTrailing = true; // Enable Trailing Stop
input int InpTrailingStart = 500; // Start Trailing After Profit (Points)
input int InpTrailingDist = 500; // Trailing Distance (Points)
input int InpTrailingStep = 50; // Trailing Step (Points)
input group "TDI Settings"
input int InpRSI_Period = 13; // RSI Period
input int InpBand_Period = 34; // Volatility Band Period
input double InpBand_Std = 1.6185; // Volatility Band Std Dev
input int InpGreen_Period = 2; // RSI Price Line (Green)
input int InpRed_Period = 7; // Trade Signal Line (Red)
input group "Filter Settings"
input int InpEMA_Period = 10; // Momentum Filter (EMA)
input int InpTrend_Period = 200; // Trend Filter (SMA)
//--- Global Objects
CTrade m_trade;
CPositionInfo m_position;
COrderInfo m_order;
//--- Indicator Handles
int hRSI; // Base RSI
int hTDI_Green; // SMA(2) of RSI
int hTDI_Red; // SMA(7) of RSI
int hStoch; // Stochastic
int hEMA; // Price EMA 10
int hTrend; // Price SMA 200
//--- Buffers (Resizing managed automatically by CopyBuffer)
double bufRSI[];
double bufGreen[];
double bufRed[];
double bufStochK[];
double bufStochD[];
double bufEMA[];
double bufTrend[];
//--- Time Management
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 1. Initialize Trade Object
m_trade.SetExpertMagicNumber(InpMagic);
m_trade.SetMarginMode();
m_trade.SetTypeFillingBySymbol(Symbol());
// 2. Indicator Handles
// --- TDI Construction ---
// Base RSI
hRSI = iRSI(Symbol(), Period(), InpRSI_Period, PRICE_CLOSE);
if(hRSI == INVALID_HANDLE) { Print("Failed to create RSI handle"); return INIT_FAILED; }
// Green Line: MA(2) applied to RSI handle
hTDI_Green = iMA(Symbol(), Period(), InpGreen_Period, 0, MODE_SMA, hRSI);
if(hTDI_Green == INVALID_HANDLE) { Print("Failed to create TDI Green handle"); return INIT_FAILED; }
// Red Line: MA(7) applied to RSI handle
hTDI_Red = iMA(Symbol(), Period(), InpRed_Period, 0, MODE_SMA, hRSI);
if(hTDI_Red == INVALID_HANDLE) { Print("Failed to create TDI Red handle"); return INIT_FAILED; }
// Note: We don't strictly *need* the bands for the specific Buy Signal logic (Green Cross Red),
// but if you wanted Squeeze logic, we'd add Bands here. For Master Plan v1, Cross is sufficient.
// --- Stochastic ---
hStoch = iStochastic(Symbol(), Period(), 5, 3, 3, MODE_SMA, STO_LOWHIGH);
if(hStoch == INVALID_HANDLE) { Print("Failed to create Stoch handle"); return INIT_FAILED; }
// --- Filters ---
hEMA = iMA(Symbol(), Period(), InpEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
if(hEMA == INVALID_HANDLE) { Print("Failed to create EMA handle"); return INIT_FAILED; }
hTrend = iMA(Symbol(), Period(), InpTrend_Period, 0, MODE_SMA, PRICE_CLOSE);
if(hTrend == INVALID_HANDLE) { Print("Failed to create Trend handle"); return INIT_FAILED; }
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(hRSI);
IndicatorRelease(hTDI_Green);
IndicatorRelease(hTDI_Red);
IndicatorRelease(hStoch);
IndicatorRelease(hEMA);
IndicatorRelease(hTrend);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check For Time Exits (Every Tick)
CheckTimeExits();
// 1b. Check Trailing Stop (Every Tick)
if(InpUseTrailing) CheckTrailingStop();
// 2. Check for New Bar (Entry Logic)
if(!IsNewBar()) return;
// 3. Data Buffers Copy (We need Index 1 and 2 for crossovers)
// We copy 3 values: [0] current, [1] closed, [2] prev-closed
if(CopyBuffer(hTDI_Green, 0, 0, 3, bufGreen) < 3) return;
if(CopyBuffer(hTDI_Red, 0, 0, 3, bufRed) < 3) return;
if(CopyBuffer(hStoch, 0, 0, 3, bufStochK) < 3) return;
if(CopyBuffer(hStoch, 1, 0, 3, bufStochD) < 3) return; // Buffer 1 is Signal line in Stoch
if(CopyBuffer(hEMA, 0, 0, 3, bufEMA) < 3) return;
if(CopyBuffer(hTrend, 0, 0, 3, bufTrend) < 3) return;
// MQL5 Arrays are index 0 = oldest by default for CopyBuffer?
// Actually defaults are 0 = start index.
// Using ArraySetAsSeries(true) makes 0 = newest (Current Bar).
ArraySetAsSeries(bufGreen, true);
ArraySetAsSeries(bufRed, true);
ArraySetAsSeries(bufStochK, true);
ArraySetAsSeries(bufStochD, true);
ArraySetAsSeries(bufEMA, true);
ArraySetAsSeries(bufTrend, true);
// Get Price Data for Candle 1
double close1 = iClose(Symbol(), Period(), 1);
double high1 = iHigh(Symbol(), Period(), 1);
double low1 = iLow(Symbol(), Period(), 1);
// --- FRIDAY FILTER ---
MqlDateTime dt;
TimeCurrent(dt);
if(dt.day_of_week == 5) return; // Do not enter on Friday
// --- SIGNAL LOGIC ---
// 1. TDI Cross UP (Green crosses Red)
// Current Closed (1) > Red AND Prev (2) <= Red
bool tdiCross = (bufGreen[1] > bufRed[1]) && (bufGreen[2] <= bufRed[2]);
// 2. Stoch Cross UP
bool stochCross = (bufStochK[1] > bufStochD[1]) && (bufStochK[2] <= bufStochD[2]);
// 3. EMA Filter (Close > EMA)
bool momentumOk = (close1 > bufEMA[1]);
// 4. Trend Filter (Close > SMA 200)
bool trendOk = (close1 > bufTrend[1]);
// --- EXECUTION ---
if(tdiCross && stochCross && momentumOk && trendOk)
{
// --- SPLIT ENTRY LOGIC ---
double sl_price = close1 - (InpStopLoss * _Point);
double tp_price = close1 + (InpTakeProfit * _Point);
// Calculate Normalized Prices
double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
sl_price = NormalizeDouble(sl_price, _Digits);
tp_price = NormalizeDouble(tp_price, _Digits);
// Trade A: Market Buy (50% Lots)
// Note: We assume InpLots is the Total Risk. So we divide by 2?
// Or InpLots is per trade. Let's assume InpLots is TOTAL SIZE.
double splitLot = NormalizeDouble(InpLots / 2.0, 2);
if(splitLot < SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN))
splitLot = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
m_trade.Buy(splitLot, Symbol(), ask, sl_price, tp_price, "TDI Market");
// Trade B: Limit Buy (50% Lots)
// FIX: Add Spread Buffer to ensure fill.
// Ask must hit Limit. If we place at Bid MidPrice, Ask is higher by Spread.
// So we lift the limit by the Spread.
// Use Ask-Bid to get the exact spread at this moment.
double market_spread = ask - SymbolInfoDouble(Symbol(), SYMBOL_BID);
double midPrice = (high1 + low1) / 2.0;
// Add Spread to Limit to ensure Ask touches it when Bid touches Mid
midPrice = midPrice + market_spread;
midPrice = NormalizeDouble(midPrice, _Digits);
// Limit SL/TP
double limit_sl = midPrice - (InpStopLoss * _Point);
double limit_tp = midPrice + (InpTakeProfit * _Point);
limit_sl = NormalizeDouble(limit_sl, _Digits);
limit_tp = NormalizeDouble(limit_tp, _Digits);
// Expiration: 4 Hours (16200 sec approx, or TimeCurrent + 4*3600)
datetime expiry = TimeCurrent() + (4 * 3600);
m_trade.BuyLimit(splitLot, midPrice, Symbol(), limit_sl, limit_tp, ORDER_TIME_SPECIFIED, expiry, "TDI Pullback");
}
}
//+------------------------------------------------------------------+
//| Check if New Bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currTime = iTime(Symbol(), Period(), 0);
if(currTime != lastBarTime)
{
lastBarTime = currTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check Time Exits |
//+------------------------------------------------------------------+
void CheckTimeExits()
{
// Loop all open positions
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(m_position.SelectByIndex(i))
{
if(m_position.Symbol() == Symbol() && m_position.Magic() == InpMagic)
{
// Calculate duration in seconds
long duration = TimeCurrent() - m_position.Time();
// Convert hours to seconds
if(duration > (InpTimeExitHours * 3600))
{
m_trade.PositionClose(m_position.Ticket());
Print("Time Exit Triggered for Ticket: ", m_position.Ticket());
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check Trailing Stop Logic |
//+------------------------------------------------------------------+
void CheckTrailingStop()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(m_position.SelectByIndex(i))
{
if(m_position.Symbol() == Symbol() && m_position.Magic() == InpMagic)
{
if(m_position.PositionType() == POSITION_TYPE_BUY)
{
double currentPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID);
double openPrice = m_position.PriceOpen();
double currentProfitPoints = (currentPrice - openPrice) / SymbolInfoDouble(Symbol(), SYMBOL_POINT);
// Start Trailing if Profit > TrailingStart
if(currentProfitPoints > InpTrailingStart)
{
double newSL = currentPrice - (InpTrailingDist * SymbolInfoDouble(Symbol(), SYMBOL_POINT));
double currentSL = m_position.StopLoss();
// Check if New SL is an improvement (Higher than current)
// And check if change is significant enough (TrailingStep)
if(newSL > currentSL + (InpTrailingStep * SymbolInfoDouble(Symbol(), SYMBOL_POINT)))
{
// Normalize
newSL = NormalizeDouble(newSL, _Digits);
double tp = m_position.TakeProfit();
// Modify
if(m_trade.PositionModify(m_position.Ticket(), newSL, tp))
{
// Success
}
}
}
}
}
}
}
}
//+------------------------------------------------------------------+