306 lines
No EOL
23 KiB
MQL5
306 lines
No EOL
23 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Fuzzy logic for fuzzy algotraders.mq5 |
|
|
//| Copyright 2017, Dmitrievskiy Max. |
|
|
//| https://www.mql5.com/ru/users/dmitrievsky |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2017, Dmitrievskiy Max."
|
|
#property link "https://www.mql5.com/ru/users/dmitrievsky"
|
|
#property version "1.00"
|
|
#include <Math\Fuzzy\MamdaniFuzzySystem.mqh>
|
|
#include <Trade\AccountInfo.mqh>
|
|
#include <MT4Orders.mqh>
|
|
|
|
CMamdaniFuzzySystem *OurFuzzy=new CMamdaniFuzzySystem();
|
|
|
|
CFuzzyVariable *firstInput=new CFuzzyVariable("rsi1",0.0,1.0);
|
|
CFuzzyVariable *secondInput=new CFuzzyVariable("rsi2",0.0,1.0);
|
|
CFuzzyVariable *thirdInput=new CFuzzyVariable("rsi3",0.0,1.0);
|
|
CFuzzyVariable *fuzzyOut=new CFuzzyVariable("out",0.0,1.0);
|
|
|
|
CDictionary_Obj_Double *firstTerm=new CDictionary_Obj_Double;
|
|
CDictionary_Obj_Double *secondTerm=new CDictionary_Obj_Double;
|
|
CDictionary_Obj_Double *thirdTerm=new CDictionary_Obj_Double;
|
|
CDictionary_Obj_Double *Output;
|
|
|
|
CMamdaniFuzzyRule *rule1, *rule2, *rule3, *rule4, *rule5, *rule6, *rule7, *rule8, *rule9, *rule10, *rule11, *rule12;
|
|
|
|
CList *Inputs=new CList;
|
|
|
|
int hnd1, hnd2, hnd3;
|
|
double arr1[], arr2[], arr3[];
|
|
|
|
input string Fuzzy_Setings; //Fuzzy optimization settings
|
|
input double Gsigma = 0.5; //sigma From 0.05 to 0.5 with 0.05 step
|
|
input double Gposition=0.5; //position From 0.0 to 1.0 with 0.1 step
|
|
input double MinNeutralSignal=0.4; //MinNeutralSignal from 0.3 to 0.5 with 0.1 step
|
|
input double MaxNeutralSignal=0.6; //MaxNeutralSignal from 0.5 to 0.7 with 0.1 step
|
|
|
|
input string Lotsettings; //Trade settings
|
|
input double MaximumRisk=0.01;
|
|
input double CustomLot=0;
|
|
input int OrderMagic=666;
|
|
|
|
double lots;
|
|
static datetime last_time=0;
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//---
|
|
Inputs.FreeMode(false);
|
|
hnd1 = iRSI(_Symbol,0,9,PRICE_CLOSE);
|
|
hnd2 = iRSI(_Symbol,0,14,PRICE_CLOSE);
|
|
hnd3 = iRSI(_Symbol,0,21,PRICE_CLOSE);
|
|
|
|
|
|
firstInput.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
|
|
firstInput.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(0.5, 0.2)));
|
|
firstInput.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
|
|
OurFuzzy.Input().Add(firstInput);
|
|
|
|
secondInput.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
|
|
secondInput.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(0.5, 0.2)));
|
|
secondInput.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
|
|
OurFuzzy.Input().Add(secondInput);
|
|
|
|
thirdInput.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
|
|
thirdInput.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(0.5, 0.2)));
|
|
thirdInput.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
|
|
OurFuzzy.Input().Add(thirdInput);
|
|
|
|
fuzzyOut.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
|
|
fuzzyOut.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(Gposition, Gsigma)));
|
|
fuzzyOut.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
|
|
OurFuzzy.Output().Add(fuzzyOut);
|
|
|
|
rule1 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is buy) and (rsi3 is buy) then (out is buy)");
|
|
rule2 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is sell) and (rsi3 is sell) then (out is sell)");
|
|
rule3 = OurFuzzy.ParseRule("if (rsi1 is neutral) and (rsi2 is neutral) and (rsi3 is neutral) then (out is neutral)");
|
|
|
|
rule4 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is sell) and (rsi3 is buy) then (out is neutral)");
|
|
rule5 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is sell) and (rsi3 is buy) then (out is neutral)");
|
|
rule6 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is buy) and (rsi3 is sell) then (out is neutral)");
|
|
|
|
rule7 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is buy) and (rsi3 is neutral) then (out is buy)");
|
|
rule8 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is sell) and (rsi3 is neutral) then (out is sell)");
|
|
rule9 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is neutral) and (rsi3 is buy) then (out is buy)");
|
|
rule10 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is neutral) and (rsi3 is sell) then (out is sell)");
|
|
rule11 = OurFuzzy.ParseRule("if (rsi1 is neutral) and (rsi2 is buy) and (rsi3 is buy) then (out is buy)");
|
|
rule12 = OurFuzzy.ParseRule("if (rsi1 is neutral) and (rsi2 is sell) and (rsi3 is sell) then (out is sell)");
|
|
|
|
|
|
OurFuzzy.Rules().Add(rule1);
|
|
OurFuzzy.Rules().Add(rule2);
|
|
OurFuzzy.Rules().Add(rule3);
|
|
OurFuzzy.Rules().Add(rule4);
|
|
OurFuzzy.Rules().Add(rule5);
|
|
OurFuzzy.Rules().Add(rule6);
|
|
OurFuzzy.Rules().Add(rule7);
|
|
OurFuzzy.Rules().Add(rule8);
|
|
OurFuzzy.Rules().Add(rule9);
|
|
OurFuzzy.Rules().Add(rule10);
|
|
OurFuzzy.Rules().Add(rule11);
|
|
OurFuzzy.Rules().Add(rule12);
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//---
|
|
Inputs.FreeMode(true);
|
|
delete Inputs;
|
|
delete OurFuzzy;
|
|
ChartRedraw();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//---
|
|
if(!isNewBar())
|
|
{
|
|
return;
|
|
}
|
|
|
|
double TradeSignal=CalculateMamdani();
|
|
|
|
if(CountOrders(0)!=0 || CountOrders(1)!=0)
|
|
{
|
|
for(int b=OrdersTotal()-1; b>=0; b--)
|
|
{
|
|
if(OrderSelect(b,SELECT_BY_POS)==true)
|
|
{
|
|
if(OrderSymbol()==_Symbol && OrderMagicNumber()==OrderMagic)
|
|
{
|
|
if(OrderType()==OP_BUY && TradeSignal>=MinNeutralSignal)
|
|
{
|
|
if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,Red))
|
|
{
|
|
if(TradeSignal>MaxNeutralSignal)
|
|
{
|
|
lots = LotsOptimized();
|
|
if(OrderSend(Symbol(),OP_SELL,lots,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0,0,NULL,OrderMagic,Red)){
|
|
};
|
|
}
|
|
}
|
|
}
|
|
if(OrderType()==OP_SELL && TradeSignal<=MaxNeutralSignal)
|
|
{
|
|
if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,Red))
|
|
{
|
|
if(TradeSignal<MinNeutralSignal)
|
|
{
|
|
lots = LotsOptimized();
|
|
if(OrderSend(Symbol(),OP_BUY,lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0,0,NULL,OrderMagic,Green)){
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
lots = LotsOptimized();
|
|
if(TradeSignal<MinNeutralSignal && CheckMoneyForTrade(_Symbol,lots,ORDER_TYPE_BUY))
|
|
{
|
|
if(OrderSend(Symbol(),OP_BUY,lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0,0,NULL,OrderMagic,Green)){
|
|
};
|
|
}
|
|
else if(TradeSignal>MaxNeutralSignal && CheckMoneyForTrade(_Symbol,lots,ORDER_TYPE_SELL))
|
|
{
|
|
if(OrderSend(Symbol(),OP_SELL,lots,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0,0,NULL,OrderMagic,Red)){
|
|
};
|
|
}
|
|
return;
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
double CalculateMamdani()
|
|
{
|
|
CopyBuffer(hnd1,0,0,1,arr1);
|
|
NormalizeArrays(arr1);
|
|
|
|
CopyBuffer(hnd2,0,0,1,arr2);
|
|
NormalizeArrays(arr2);
|
|
|
|
CopyBuffer(hnd3,0,0,1,arr3);
|
|
NormalizeArrays(arr3);
|
|
|
|
firstTerm.SetAll(firstInput,arr1[0]);
|
|
secondTerm.SetAll(secondInput,arr2[0]);
|
|
thirdTerm.SetAll(thirdInput,arr2[0]);
|
|
|
|
Inputs.Clear();
|
|
Inputs.Add(firstTerm);
|
|
Inputs.Add(secondTerm);
|
|
Inputs.Add(thirdTerm);
|
|
|
|
CList *FuzzResult=OurFuzzy.Calculate(Inputs);
|
|
Output=FuzzResult.GetNodeAtIndex(0);
|
|
double res = Output.Value();
|
|
delete FuzzResult;
|
|
|
|
return(res);
|
|
}
|
|
|
|
void NormalizeArrays(double &a[])
|
|
{
|
|
double d1=0;
|
|
double d2=1.0;
|
|
double x_min=0.0;
|
|
double x_max=100;
|
|
for(int i=0;i<ArraySize(a);i++)
|
|
{
|
|
a[i]=(((a[i]-x_min)*(d2-d1))/(x_max-x_min))+d1;
|
|
}
|
|
}
|
|
|
|
int CountOrders(int a)
|
|
{
|
|
int result=0;
|
|
for(int k=0; k<OrdersTotal(); k++)
|
|
{
|
|
if(OrderSelect(k,SELECT_BY_POS,MODE_TRADES)==true)
|
|
{
|
|
if(OrderType()==a && OrderMagicNumber()==OrderMagic && OrderSymbol()==_Symbol)
|
|
{result++;}
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
double LotsOptimized()
|
|
{
|
|
CAccountInfo myaccount; SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
|
|
double lot;
|
|
|
|
lot=NormalizeDouble(myaccount.FreeMargin()*MaximumRisk/1000.0,2);
|
|
if(CustomLot!=0.0) lot=CustomLot;
|
|
|
|
double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
|
|
int ratio=(int)MathRound(lot/volume_step);
|
|
if(MathAbs(ratio*volume_step-lot)>0.0000001)
|
|
{
|
|
lot = ratio*volume_step;
|
|
}
|
|
if(lot<SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN)) lot=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
|
|
if(lot>SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX)) lot=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
|
|
return(lot);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool isNewBar()
|
|
{
|
|
datetime lastbar_time=datetime(SeriesInfoInteger(Symbol(),_Period,SERIES_LASTBAR_DATE));
|
|
if(last_time==0)
|
|
{
|
|
last_time=lastbar_time;
|
|
return(false);
|
|
}
|
|
if(last_time!=lastbar_time)
|
|
{
|
|
last_time=lastbar_time;
|
|
return(true);
|
|
}
|
|
return(false);
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
bool CheckMoneyForTrade(string symb,double lot,ENUM_ORDER_TYPE type)
|
|
{
|
|
//--- Getting the opening price
|
|
MqlTick mqltick;
|
|
SymbolInfoTick(symb,mqltick);
|
|
double price=mqltick.ask;
|
|
if(type==ORDER_TYPE_SELL)
|
|
price=mqltick.bid;
|
|
//--- values of the required and free margin
|
|
double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
|
|
//--- call of the checking function
|
|
if(!OrderCalcMargin(type,symb,lots,price,margin))
|
|
{
|
|
//--- something went wrong, report and return false
|
|
Print("Error in ",__FUNCTION__," code=",GetLastError());
|
|
return(false);
|
|
}
|
|
//--- if there are insufficient funds to perform the operation
|
|
if(margin>free_margin)
|
|
{
|
|
//--- report the error and return false
|
|
Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
|
|
return(false);
|
|
}
|
|
//--- checking successful
|
|
return(true);
|
|
} |