276 行
10 KiB
MQL5
276 行
10 KiB
MQL5
//+------------------------------------------------------------------------+
|
|
//| TDI_Stoch_Classic.mq5 |
|
|
//| Copyright Ruben Works |
|
|
//| |
|
|
//+------------------------------------------------------------------------+
|
|
#property copyright "Ruben Works"
|
|
#property link ""
|
|
#property version "1.00"
|
|
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\PositionInfo.mqh>
|
|
|
|
//--- Input Parameters
|
|
input group "Strategy Settings"
|
|
input double InpLots = 0.1; // Lot Size
|
|
input int InpStopLoss = 7500; // Stop Loss (Points, Safe Default)
|
|
input int InpTakeProfit = 3000; // Take Profit (Points)
|
|
input int InpMagic = 111222; // Magic Number
|
|
input int InpTimeExitHours = 16; // Max Holding Time (Hours)
|
|
|
|
input group "TDI Settings"
|
|
input int InpRSI_Period = 13; // RSI Period
|
|
input int InpGreen_Period = 2; // RSI Price Line (Green)
|
|
input int InpRed_Period = 7; // Trade Signal Line (Red)
|
|
|
|
input group "Filter Settings"
|
|
input bool InpUseETV = false; // Easy Trend Visualizer (Sniper Mode)
|
|
|
|
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)
|
|
|
|
//--- Global Objects
|
|
CTrade m_trade;
|
|
CPositionInfo m_position;
|
|
|
|
//--- Indicator Handles
|
|
int hRSI; // Base RSI
|
|
int hTDI_Green; // SMA(2) of RSI
|
|
int hTDI_Red; // SMA(7) of RSI
|
|
int hStoch; // Stochastic
|
|
|
|
// ETV Handles
|
|
int hADX10;
|
|
int hADX14;
|
|
int hADX20;
|
|
|
|
//--- Buffers
|
|
double bufGreen[];
|
|
double bufRed[];
|
|
double bufStochK[];
|
|
double bufStochD[];
|
|
|
|
// ETV Buffers
|
|
double bufADX10[], bufPlus10[], bufMinus10[];
|
|
double bufADX14[];
|
|
double bufADX20[];
|
|
|
|
//--- 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 ---
|
|
hRSI = iRSI(Symbol(), Period(), InpRSI_Period, PRICE_CLOSE);
|
|
if(hRSI == INVALID_HANDLE) { Print("Failed to create RSI handle"); return INIT_FAILED; }
|
|
|
|
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; }
|
|
|
|
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; }
|
|
|
|
// --- 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; }
|
|
|
|
// --- ETV Handles ---
|
|
hADX10 = iADX(Symbol(), Period(), 10);
|
|
if(hADX10 == INVALID_HANDLE) { Print("Failed to create ADX 10"); return INIT_FAILED; }
|
|
|
|
hADX14 = iADX(Symbol(), Period(), 14);
|
|
if(hADX14 == INVALID_HANDLE) { Print("Failed to create ADX 14"); return INIT_FAILED; }
|
|
|
|
hADX20 = iADX(Symbol(), Period(), 20);
|
|
if(hADX20 == INVALID_HANDLE) { Print("Failed to create ADX 20"); 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(hADX10);
|
|
IndicatorRelease(hADX14);
|
|
IndicatorRelease(hADX20);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// 1. Check For Time/Trailing Exits (Every Tick)
|
|
CheckTimeExits();
|
|
if(InpUseTrailing) CheckTrailingStop();
|
|
|
|
// 2. Check for New Bar (Entry Logic)
|
|
if(!IsNewBar()) return;
|
|
|
|
// 3. Data Buffers Copy
|
|
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;
|
|
|
|
ArraySetAsSeries(bufGreen, true);
|
|
ArraySetAsSeries(bufRed, true);
|
|
ArraySetAsSeries(bufStochK, true);
|
|
ArraySetAsSeries(bufStochD, true);
|
|
|
|
double close1 = iClose(Symbol(), Period(), 1);
|
|
|
|
// --- SIGNAL LOGIC (Classic) ---
|
|
|
|
// 1. TDI Cross UP (Green crosses Red)
|
|
bool tdiCross = (bufGreen[1] > bufRed[1]) && (bufGreen[2] <= bufRed[2]);
|
|
|
|
// 2. Stoch Cross UP (K crosses D)
|
|
bool stochCross = (bufStochK[1] > bufStochD[1]) && (bufStochK[2] <= bufStochD[2]);
|
|
|
|
// 3. ETV Filter
|
|
bool etvOk = true;
|
|
if(InpUseETV)
|
|
{
|
|
etvOk = (CheckETV() == 1);
|
|
}
|
|
|
|
// --- EXECUTION (Simple Market Buy) ---
|
|
if(tdiCross && stochCross && etvOk)
|
|
{
|
|
double sl_price = close1 - (InpStopLoss * _Point);
|
|
double tp_price = close1 + (InpTakeProfit * _Point);
|
|
double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
|
|
sl_price = NormalizeDouble(sl_price, _Digits);
|
|
tp_price = NormalizeDouble(tp_price, _Digits);
|
|
|
|
m_trade.Buy(InpLots, Symbol(), ask, sl_price, tp_price, "TDI Classic");
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check ETV (Easy Trend Visualizer) Logic |
|
|
//| Returns: 1 (Bull), -1 (Bear), 0 (Flat) |
|
|
//+------------------------------------------------------------------+
|
|
int CheckETV()
|
|
{
|
|
// Copy Buffers
|
|
if(CopyBuffer(hADX10, MAIN_LINE, 0, 3, bufADX10) < 3) return 0;
|
|
if(CopyBuffer(hADX14, MAIN_LINE, 0, 3, bufADX14) < 3) return 0;
|
|
if(CopyBuffer(hADX20, MAIN_LINE, 0, 3, bufADX20) < 3) return 0;
|
|
|
|
if(CopyBuffer(hADX10, PLUSDI_LINE, 0, 2, bufPlus10) < 2) return 0;
|
|
if(CopyBuffer(hADX10, MINUSDI_LINE, 0, 2, bufMinus10) < 2) return 0;
|
|
|
|
ArraySetAsSeries(bufADX10, true);
|
|
ArraySetAsSeries(bufADX14, true);
|
|
ArraySetAsSeries(bufADX20, true);
|
|
ArraySetAsSeries(bufPlus10, true);
|
|
ArraySetAsSeries(bufMinus10, true);
|
|
|
|
// 1. Check Rising (Current [1] > Prev [2])
|
|
bool rising10 = bufADX10[1] > bufADX10[2];
|
|
bool rising14 = bufADX14[1] > bufADX14[2];
|
|
bool rising20 = bufADX20[1] > bufADX20[2];
|
|
|
|
// 2. Check Levels
|
|
bool level10 = bufADX10[1] > 35;
|
|
bool level14 = bufADX14[1] > 30;
|
|
|
|
if(rising10 && rising14 && rising20 && level10 && level14)
|
|
{
|
|
// Trend Exists. Determine Direction.
|
|
if(bufPlus10[1] > bufMinus10[1]) return 1; // Bullish
|
|
if(bufPlus10[1] < bufMinus10[1]) return -1; // Bearish
|
|
}
|
|
|
|
return 0; // Flat
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Helper Functions |
|
|
//+------------------------------------------------------------------+
|
|
bool IsNewBar()
|
|
{
|
|
datetime currTime = iTime(Symbol(), Period(), 0);
|
|
if(currTime != lastBarTime) { lastBarTime = currTime; return true; }
|
|
return false;
|
|
}
|
|
|
|
void CheckTimeExits()
|
|
{
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(m_position.SelectByIndex(i))
|
|
{
|
|
if(m_position.Symbol() == Symbol() && m_position.Magic() == InpMagic)
|
|
{
|
|
if((TimeCurrent() - m_position.Time()) > (InpTimeExitHours * 3600))
|
|
m_trade.PositionClose(m_position.Ticket());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckTrailingStop()
|
|
{
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(m_position.SelectByIndex(i))
|
|
{
|
|
if(m_position.Symbol() == Symbol() && m_position.Magic() == InpMagic && m_position.PositionType() == POSITION_TYPE_BUY)
|
|
{
|
|
double currentPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
double openPrice = m_position.PriceOpen();
|
|
double profitPts = (currentPrice - openPrice) / SymbolInfoDouble(Symbol(), SYMBOL_POINT);
|
|
|
|
if(profitPts > InpTrailingStart)
|
|
{
|
|
double newSL = currentPrice - (InpTrailingDist * SymbolInfoDouble(Symbol(), SYMBOL_POINT));
|
|
if(newSL > m_position.StopLoss() + (InpTrailingStep * SymbolInfoDouble(Symbol(), SYMBOL_POINT)))
|
|
{
|
|
m_trade.PositionModify(m_position.Ticket(), NormalizeDouble(newSL, _Digits), m_position.TakeProfit());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OnTester: Custom Optimization Criterion |
|
|
//| Returns: Recovery Factor (Net Profit / Max DD) |
|
|
//+------------------------------------------------------------------+
|
|
double OnTester()
|
|
{
|
|
double netProfit = TesterStatistics(STAT_PROFIT);
|
|
double maxDD = TesterStatistics(STAT_EQUITY_DD); // In Money
|
|
|
|
// Avoid division by zero
|
|
if(maxDD == 0.0) maxDD = 1.0;
|
|
|
|
// If negative profit, return the profit itself (negative value)
|
|
if(netProfit < 0) return netProfit;
|
|
|
|
return netProfit / maxDD;
|
|
}
|