ictCore/Experts/preReleasedBots/momo.mq5

342 lines
9 KiB
MQL5
Raw Permalink Normal View History

//buy below the open
//sell above the open
#include <Trade/Trade.mqh>
#include <Trade/SymbolInfo.mqh>
//struct tfCoord
// {
// ENUM_TIMEFRAMES xtf;
// ENUM_TIMEFRAMES ytf;
// ENUM_TIMEFRAMES ztf;
// };
//
//tfCoord tf;
input double BEFactor; //multiple of rr, that will acticate lock-in
//Timeframe Coordination
input ENUM_TIMEFRAMES InpXtf; //main starting tf
input ENUM_TIMEFRAMES inpYtf; // middle linking tf
input ENUM_TIMEFRAMES inpZtf; //execution tf
input double inpLot; //preferred position size
double FixedSizeRisk;
input int inpTickClearance; // number of ticks allowed to go beyond pre-defined sl
input int inpRR; //Risk to reward ratio;
input bool inpTrigger1; //activate recieval of triggering signal from model1
extern bool trigger(); //other complex logic
//Globals
bool isAbove;
bool isBelow;
double lockIn; //this for every open position
//int beyond; //-1 for below, 1 for above
bool isNewCandle;
bool isTradeDay;
int signalFlag;
static bool hasFired = false;
int buyCounts;
int sellCounts;
//ENUM_TIMEFRAMES tf {PERIOD_H1, PERIOD_M5, PERIOD_M1};
struct rates{
ENUM_TIMEFRAMES tf;
int beyond;
MqlRates x[]; //
int triggerFlag; //potential buy/sell catalyst
};
rates r[3];
//can instanciate rates object to look for other potential signal from another TF
CTrade trade;
CSymbolInfo symInfo;
//Forward declaration
void breakEven();
bool trigger(int &flag, int tfIndex, int candleIndex); //a reason to act
bool IsNewCandle() {
static datetime lastTime = 0;
datetime currentTime = iTime(_Symbol, inpZtf, 0);
if(lastTime != currentTime) {
lastTime = currentTime;
return true;
}
return false;
}
int OnInit(void)
{
//initiate vars
signalFlag=0;
//Validating user input var
if((InpXtf<inpYtf) || (inpYtf<inpZtf)){
Alert(" Input Timeframe doesn't enable Top-Down Approach");
return (INIT_PARAMETERS_INCORRECT);
}
//else
//assigning selected tf
r[0].tf=InpXtf;
r[1].tf=inpYtf;
r[2].tf=inpZtf;
for(int i=0;i<ArraySize(r);++i){
r[i].triggerFlag=0; //Neutral
}
//lot
if(inpLot<SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN/*symbol's lowest lot*/)){
Alert("ERROR! could not accept lot be less than ",SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN));
return (INIT_PARAMETERS_INCORRECT);
}
if(inpRR<0){ /*negative r*/
Alert("RR cant be less than 0");
return(INIT_PARAMETERS_INCORRECT);
}
//if(<)
riskManagement();
//if(FixedSizeRisk<SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)) return (INIT_PARAMETERS_INCORRECT);
Print(FixedSizeRisk);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int32_t reason)
{
Print("sell signals:",sellCounts," buy signals:",buyCounts);
}
void updateRates(){
for(int i=0;i<ArraySize(r);i++){
//for(int j=0;j<enumtotal;j++)
CopyRates(Symbol(),r[i].tf,0,5,r[i].x);
ArraySetAsSeries(r[i].x,true);
if(r[i].x[0].close>r[i].x[0].open){ //current price trading above the opening
r[i].beyond=1;
}
else if(r[i].x[0].close<r[i].x[0].open){ //current price trading below the opening
r[i].beyond=-1;
}
else r[i].beyond=0;
}
}
void OnTick(){
////
// CopyRates(Symbol(),PERIOD_CURRENT,0,5,r.x);
// ArraySetAsSeries(r.x,true);
//
// if(r.x[0].close>r.x[0].open){ //current price trading above the opening
// beyond=1;
// }
// else if(r.x[0].close<r.x[0].open){ //current price trading below the opening
// beyond=-1;
// }
// else beyond=0;
updateRates();
//whenever you add a position assign a struct to
breakEven(BEFactor);
if(IsNewCandle()) {
hasFired = false;
}
//trigger monitoring
for(int i=0;i<ArraySize(r);i++){
//if(inpTrigger1)
trigger(r[i].triggerFlag,i);
//else
//trigger(r[i].triggerFlag,i);
}
//Signal processing
signal();
string signalCall;
if(signalFlag==1){signalCall="BUY BUY BUY";}
else if(signalFlag==-1){signalCall="SELL SELL SELL";}
//entering a trade
//STATE MONITORING
Comment("Beyond || Trigger :","\nXTF=",r[0].beyond," || ",r[0].triggerFlag,"\nYTF=",r[1].beyond," || ",r[1].triggerFlag,"\nZTF=",r[2].beyond," || ",r[2].triggerFlag,"\nBE factor: ",BEFactor,"\n",signalCall);
//SymbolSelect(_Symbol,true);
//Alert();
}
void breakEven(const double factor /*, double &lockIn*/){
//accept a factor as a multiple of RR (USER INPUT) suggest to lock-in the position into a risk free
//SAFE GUARD
if(PositionsTotal()<1){ //no open position to BE
return;
}
if(factor<1){
Print(__FUNCTION__,"ERROR Factor for BE provided was less than 1");
return;
}
double spread = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * _Point;
for(int i=PositionsTotal()-1;i>=0;--i){
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol) {
double sl=PositionGetDouble(POSITION_SL);
double tp=PositionGetDouble(POSITION_TP);
double entryPrice=PositionGetDouble(POSITION_PRICE_OPEN);
double risk=MathAbs(entryPrice-sl);
int posType = (int)PositionGetInteger(POSITION_TYPE);
double BEPoint=factor*risk;
double newSL=0;
// Calculate lock-in price based on position type
if(posType==POSITION_TYPE_BUY){
lockIn=entryPrice+BEPoint;
}
else if(posType==POSITION_TYPE_SELL){
lockIn=entryPrice-BEPoint;
}
// Check if price has crossed the lock-in threshold
if(r[0].x[0].high>lockIn && r[0].x[0].low<lockIn){
// Aggressively adjust SL to spread + entry price (always breakeven+spread)
if(posType==POSITION_TYPE_BUY){
newSL = entryPrice + spread; // Entry + spread = breakeven point
}
else if(posType==POSITION_TYPE_SELL){
newSL = entryPrice - spread; // Entry - spread = breakeven point
}
// Only modify if new SL is better than current SL
if((posType==POSITION_TYPE_BUY && newSL>sl) || (posType==POSITION_TYPE_SELL && newSL<sl)){
if(trade.PositionModify(ticket,newSL,tp)){
Alert("B.E successful - SL adjusted to ", newSL);
}
}
}
}
}
}
//
//bool trigger(int &flag, int tfIndex=0, int candleIndex=1){
// if(r[tfIndex].x[candleIndex].close>r[tfIndex].x[candleIndex+1].high){
// //bullish catalyst
// flag=1;
// return true;
// }
// else if(r[tfIndex].x[candleIndex].close<r[tfIndex].x[candleIndex+1].low){
// //bearish catalyst
// flag=-1;
// return true;
// }
// else flag=0;//close inside range
//
//return false;
//}
//
bool trigger(int &flag, int tfIndex=0, int candleIndex=1){
double upper=r[tfIndex].x[candleIndex].high-MathMax(r[tfIndex].x[candleIndex].open,r[tfIndex].x[candleIndex].close);
double lower=MathMin(r[tfIndex].x[candleIndex].open,r[tfIndex].x[candleIndex].close)-r[tfIndex].x[candleIndex].low;
if(upper>lower//bearish momentum candle
&&(r[tfIndex].x[candleIndex].low>r[tfIndex].x[candleIndex+1].low)){
//bearish catalyst
flag=-1;
return true;
}
if(lower>upper//bullish momentum candle
&&(r[tfIndex].x[candleIndex].high<r[tfIndex].x[candleIndex+1].high)){
//bullish catalyst
flag=1;
return true;
}
return false;
}
bool signal() {
// 1. Define the Alignments
bool bullishAlignment = (r[0].triggerFlag==1 && r[0].beyond==-1 &&
r[1].triggerFlag==1 && r[1].beyond==-1 &&
r[2].triggerFlag==1 && r[2].beyond==-1);
bool bearishAlignment = (r[0].triggerFlag==-1 && r[0].beyond==1 &&
r[1].triggerFlag==-1 && r[1].beyond==1 &&
r[2].triggerFlag==-1 && r[2].beyond==1);
// 2. Handle the Buy
if(bullishAlignment) {
if(!hasFired) {
trade.Buy(inpLot, _Symbol, r[2].x[0].close, (r[2].x[0].close-FixedSizeRisk), (r[2].x[0].close+(FixedSizeRisk*inpRR)));
buyCounts++;
hasFired = true;
Alert("Buy Executed");
}
return true;
}
// 3. Handle the Sell
if(bearishAlignment) {
if(!hasFired) {
sellCounts++;
trade.Sell(inpLot, _Symbol, r[2].x[0].close, (r[2].x[0].close+FixedSizeRisk), (r[2].x[0].close-(FixedSizeRisk*inpRR)));
hasFired = true;
Alert("Sell Executed");
}
return true;
}
// 4. Reset if NO alignment exists
//else {
// hasFired = false;
//}
return false;
}
void riskManagement() {
double spread = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * _Point;
double minStop = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
// Allow just above minimum required: minStop + spread + clearance
FixedSizeRisk = MathMax(minStop + spread + (inpTickClearance * _Point), spread * 1.5);
}