NorthfoxTrueEdge/Projektipäiväkirja/ Modattu ja integroitu versio.mq5
super.admin 639c303b4b convert
2025-05-30 16:13:38 +02:00

471 lines
39 KiB
MQL5

//+------------------------------------------------------------------+
//| isBoS_MSS_Robot.mq5 |
//| Kaupankäyntirobotti v1.0 |
//| Copyright 2024, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade/Trade.mqh>
CTrade obj_Trade;
/*
Projektipäiväkirja: Kaupankäyntirobotin Kehitys ja Optimointi
Projektin nimi: Kaupankäyntirobotti (isBoS, MSS ja signaalivahvistukset)
Tavoite: Rakentaa automaattinen robotti, joka hyödyntää strategioita kuten MSS, BOS,
M1 salamavahvistus, ADR, TDFI ja ADX-trendin vahvistus sekä riskienhallinnan.
*/
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
/*
1.1 Projektin määrittely ja dokumentaatio (VALMIS)
Tehtävä: Määrittele projektin tavoitteet, strategiat ja kriteerit, kuten MSS, BOS, ADX,
M1-vahvistus ja kaupankäynnin hallinta.
Valmis, kun: Projektin tavoitteet, strategiat ja toimintaperiaatteet ovat selkeästi dokumentoitu.
*/
//--- Input parameters
input int StopLoss = 30; // Stop Loss in pips
input int TakeProfit = 100; // Take Profit in pips
input int ADX_Period = 14; // ADX Period
input int MA_Period = 200; // Moving Average Period
int MagicNumber = 0; // EA Magic Number
input double Adx_Min = 25.0; // Minimum ADX Value
input double Lot = 0.1; // Lots to Trade
input int length = 20; // BOS vanha length = 20;
input int limit = 20; // BOS vanha limit = 20;
//--- Other parameters
int adxHandle; // Handle for ADX indicator
int maHandle; // Handle for Moving Average indicator
double TDFIHandle; // Handle for tdfi
double plsDI[], minDI[], adxVal[]; // Dynamic arrays for indicators
double maVal[]; // Dynamic array for Moving Average
double TDFIVal[];
double previousClose; // Variable to store the close value of the previous bar
int stopLossPips, takeProfitPips; // Variables for Stop Loss & Take Profit values
int TDFI0=0;
int OnInit(){
Print("Kaupankäyntirobotin kehitys aloitettu");
MagicNumber=sub_magicnumber();
//--- Get handles for indicators
adxHandle = iADX(NULL, 0, ADX_Period);
maHandle = iMA(_Symbol, _Period, MA_Period, 0, MODE_EMA, PRICE_CLOSE);
// TDFIHandle =iCustom(_Symbol, _Period, "trend-direction-and-force", 20, 1, PRICE_CLOSE, 0.05, -0.05, 5, 0, 2, 0);
//--- Check for valid handles
if (adxHandle < 0 || maHandle < 0 )//|| TDFIHandle < 0)
{
Alert("Error creating handles for indicators - error: ", GetLastError(), "!!");
return INIT_FAILED;
}
//--- Adjust Stop Loss and Take Profit for 5 or 3 digit prices
stopLossPips = StopLoss;
takeProfitPips = TakeProfit;
if (_Digits == 5 || _Digits == 3)
{
stopLossPips *= 10;
takeProfitPips *= 10;
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
/*
1.2 Työkalujen ja ympäristön valmistelu (VALMIS)
Tehtävä: Asenna MetaTrader 5, koodieditori (esim. Visual Studio) ja GitHub yhteiskoodaukseen.
Valmis, kun: Kaikki työkalut ja ohjelmistot on asennettu ja testattu.
*/
void OnDeinit(const int reason){
Print("Kaupankäyntirobotin kehitys lopetettu");
IndicatorRelease(adxHandle);
IndicatorRelease(maHandle);
// IndicatorRelease(TDFIHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
//--- Ensure there are enough bars to work with
if (Bars(_Symbol, _Period) < 60)
{
Alert("We have less than 60 bars, EA will now exit!!");
return;
}
/*
2.1 Kaupankäyntistrategioiden Peruslogiikan Implementointi
Luo peruslogiikka Break and Retest, isBoS ja MSS-strategioille.
*/
static bool isNewBar = false;
int currBars = iBars(_Symbol,_Period);
static int prevBars = currBars;
if (prevBars == currBars){isNewBar = false;}
else if (prevBars != currBars){isNewBar = true; prevBars = currBars;}
// const int length = 20; // vanha length = 20;
// const int limit = 20; // vanha limit = 20;
int right_index, left_index;
bool isSwingHigh = true, isSwingLow = true;
static double swing_H = -1.0, swing_L = -1.0;
int curr_bar = limit;
//--- Copy the new values of our ADX, MA indicators to buffers (arrays) using the handle
if(CopyBuffer(adxHandle,0,0,3,adxVal)<0 || CopyBuffer(adxHandle,1,0,3,plsDI)<0
|| CopyBuffer(adxHandle,2,0,3,minDI)<0)
{
Alert("Error copying ADX indicator Buffers - error:",GetLastError(),"!!");
return;
}
if(CopyBuffer(maHandle,0,0,3,maVal)<0)
{
Alert("Error copying Moving Average indicator buffer - error:",GetLastError());
return;
}
/*
if(CopyBuffer(TDFIHandle,2,0,1,TDFIVal)<0)
{
Alert("tdfi error:",TDFIVal[0]);
return;
}
*/
/*
2.2 MSS ja BOS -tunnistus
Luo logiikka MSS- ja BOS-mekanismeille.
*/
if (isNewBar){
for (int j=1; j<=length; j++){
right_index = curr_bar - j;
left_index = curr_bar + j;
//Print("Current Bar Index = ",curr_bar," ::: Right index: ",right_index,", Left index: ",left_index);
//Print("curr_bar(",curr_bar,") right_index = ",right_index,", left_index = ",left_index);
// If high of the current bar curr_bar is <= high of the bar at right_index (to the left),
//or if it’s < high of the bar at left_index (to the right), then isSwingHigh is set to false
//This means that the current bar curr_bar does not have a higher high compared
//to its neighbors, and therefore, it’s not a swing high
if ( (high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index)) ){
isSwingHigh = false;
}
if ( (low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index)) ){
isSwingLow = false;
}
}
//By the end of the loop, if isSwingHigh is still true, it suggests that
//current bar curr_bar has a higher high than the surrounding bars within
//length range, marking a potential swing high.
if (isSwingHigh){
swing_H = high(curr_bar);
Print("UP @ BAR INDEX ",curr_bar," of High: ",high(curr_bar));
drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),high(curr_bar),77,clrBlue,-1);
}
if (isSwingLow){
swing_L = low(curr_bar);
Print("DOWN @ BAR INDEX ",curr_bar," of Low: ",low(curr_bar));
drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),low(curr_bar),77,clrRed,1);
}
}
/*
2.3 M1 Salamavahvistus
Lisää logiikka M1-vahvistukselle ennen kaupan avaamista.
*/
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
if (!isPositionOpen(MagicNumber) && adxVal[0]>Adx_Min && close(1)<maVal[0] && //&& TDFIVal[0]>0.05
swing_H > 0 && Bid > swing_H && close(1) > swing_H){
Print("BREAK UP NOW");
// Print("TDFI:"+TDFIVal[0]);
int swing_H_index = 0;
for (int i=0; i<=length*2+1000; i++){
double high_sel = high(i);
if (high_sel == swing_H){
swing_H_index = i;
Print("BREAK HIGH @ BAR ",swing_H_index);
break;
}
}
drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index),
time(0+1),high(swing_H_index),clrBlue,-1);
swing_H = -1.0;
//--- Open Buy
//VANHA: obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY");
ExecuteBuyTrade(); //uusi
return;
}
else if (!isPositionOpen(MagicNumber) && adxVal[0]>Adx_Min && close(1)>maVal[0] && //TDFIVal[0]<-0.05 && && TDFIVal[0]<-0.05
swing_L > 0 && Ask < swing_L && close(1) < swing_L){
Print("BREAK DOWN NOW");
// Print("TDFI:"+TDFIVal[0]);
int swing_L_index = 0;
for (int i=0; i<=length*2+1000; i++){
double low_sel = low(i);
if (low_sel == swing_L){
swing_L_index = i;
Print("BREAK LOW @ BAR ",swing_L_index);
break;
}
}
drawBreakLevel(TimeToString(time(0)),time(swing_L_index),low(swing_L_index),
time(0+1),low(swing_L_index),clrRed,1);
swing_L = -1.0;
//--- Open Sell
//VANHA: obj_Trade.Sell(0.01,_Symbol,Bid,Ask+500*7*_Point,Ask-500*_Point,"BoS Break Down SELL");
ExecuteSellTrade();
return;
}
} //ontick
double high(int index){return (iHigh(_Symbol,_Period,index));}
double low(int index){return (iLow(_Symbol,_Period,index));}
double close(int index){return (iClose(_Symbol,_Period,index));}
datetime time(int index){return (iTime(_Symbol,_Period,index));}
/*
3.1 Stop Loss -tason määrittely (Fibonacci-taso 0.58)
Määritä stop loss -taso fib 0.58 -tasolle.
*/
/*
3.2 Break-Even (BE) -tason asetus
Toteuta BE-taso, johon stop loss siirtyy 1:1 voittosuhteessa.
*/
/*
3.3 Voittosuhteen (R) säätäminen 10 % tuoton jälkeen
Muuta voittosuhde 1:2-tasolle 10 % tuoton jälkeen.
*/
/*
3.4 ADX-indikaattorin käyttö trendin vahvuuden arvioinnissa
Määritä ADX-vahvuus kaupankäynnin suodattimeksi.
*/
/*
4.1 Backtesting (Takautuva testaus)
Suorita backtestejä eri markkinatilanteissa MetaTrader 5 -alustalla.
*/
/*
4.2 Koodin Optimointi ja Parametrien Hienosäätö
Optimoi robottikoodia parametrien hienosäädöllä.
*/
/*
4.3 Forward Testing (Reaaliaikainen testaus)
Testaa robotti reaaliajassa demotilillä tai pienellä live-tilillä.
*/
//+------------------------------------------------------------------+
//| Swing-pisteiden ja tasojen piirtämistoiminnot |
//+------------------------------------------------------------------+
void drawSwingPoint(string objName,datetime time,double price,int arrCode,
color clr,int direction){
if (ObjectFind(0,objName) < 0){
ObjectCreate(0,objName,OBJ_ARROW,0,time,price);
ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrCode);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,10);
if (direction > 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
if (direction < 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
string txt = " BoS";
string objNameDescr = objName + txt;
ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time,price);
ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
if (direction > 0) {
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
}
if (direction < 0) {
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
}
}
ChartRedraw(0);
}
void drawBreakLevel(string objName,datetime time1,double price1,
datetime time2,double price2,color clr,int direction){
if (ObjectFind(0,objName) < 0){
ObjectCreate(0,objName,OBJ_ARROWED_LINE,0,time1,price1,time2,price2);
ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objName,OBJPROP_WIDTH,2);
string txt = " Break ";
string objNameDescr = objName + txt;
ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time2,price2);
ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
if (direction > 0) {
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_UPPER);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
}
if (direction < 0) {
ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER);
ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
}
}
ChartRedraw(0);
}
//obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY");
bool ExecuteBuyTrade()
{
//--- Prepare trade request
MqlTradeRequest mrequest;
MqlTradeResult mresult;
ZeroMemory(mrequest); // Initialize request structure
mrequest.action = TRADE_ACTION_DEAL; // Immediate order execution
mrequest.price = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); // Latest ask price
mrequest.sl = NormalizeDouble(mrequest.price - stopLossPips * _Point, _Digits); // Stop Loss
mrequest.tp = NormalizeDouble(mrequest.price + takeProfitPips * _Point, _Digits); // Take Profit
mrequest.symbol = _Symbol; // Currency pair
mrequest.volume = Lot; // Number of lots to trade
mrequest.magic = MagicNumber; // Order Magic Number
mrequest.type = ORDER_TYPE_BUY; // Buy Order
mrequest.type_filling = ORDER_FILLING_IOC; // Order execution type
mrequest.deviation = 100; // Deviation from current price
//--- Send order
OrderSend(mrequest, mresult);
// Check order result
if (mresult.retcode == 10009 || mresult.retcode == 10008) // Request completed or order placed
{
Alert("A Buy order has been successfully placed with Ticket#:", mresult.order, "!!");
return true; // Buy order executed successfully
}
else
{
Alert("The Buy order request could not be completed - error:", GetLastError());
ResetLastError();
return false; // Buy order execution failed
}
}
//+------------------------------------------------------------------+
//| Sell trade execution function |
//+------------------------------------------------------------------+
bool ExecuteSellTrade()
{
//--- Prepare trade request
MqlTradeRequest mrequest;
MqlTradeResult mresult;
ZeroMemory(mrequest); // Initialize request structure
mrequest.action = TRADE_ACTION_DEAL; // Immediate order execution
mrequest.price = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); // Latest bid price
mrequest.sl = NormalizeDouble(mrequest.price + stopLossPips * _Point, _Digits); // Stop Loss
mrequest.tp = NormalizeDouble(mrequest.price - takeProfitPips * _Point, _Digits); // Take Profit
mrequest.symbol = _Symbol; // Currency pair
mrequest.volume = Lot; // Number of lots to trade
mrequest.magic = MagicNumber; // Order Magic Number
mrequest.type = ORDER_TYPE_SELL; // Sell Order
mrequest.type_filling = ORDER_FILLING_IOC; // Order execution type
mrequest.deviation = 100; // Deviation from current price
//--- Send order
OrderSend(mrequest, mresult);
// Check order result
if (mresult.retcode == 10009 || mresult.retcode == 10008) // Request completed or order placed
{
Alert("A Sell order has been successfully placed with Ticket#:", mresult.order, "!!");
return true; // Sell order executed successfully
}
else
{
Alert("The Sell order request could not be completed - error:", GetLastError());
ResetLastError();
return false; // Sell order execution failed
}
}
double TDFI(int shift, int trendPeriod, double smoothLength) {
// int timeFrame = _Period; // Aikakehys, käytetään nykyistä aikakehystä
int trendMethod = 1; // Keskiarvotyyppi: 1 = EMA
int priceMode = PRICE_CLOSE; // Hinta, jota käytetään: 0 = Close
double triggerUp = 0.05; // Yläraja trigger-tasolle
double triggerDown = -0.05; // Alaraja trigger-tasolle
double smoothPhase = 0; // Sileysvaihe
string indicator = "trend-direction-and-force";
// Hakee bufferin 2 arvon, jossa trenditieto sijaitsee
double trend = iCustom(NULL, _Period, indicator, trendPeriod, trendMethod, priceMode, triggerUp, triggerDown, smoothLength, smoothPhase, 2, shift);
return trend;
}
int sub_magicnumber() {
string local_a;
string local_b;
int local_c;
int local_d;
int local_i;
string local_par = "EURUSDJPYCHFCADAUDNZDGBPBTCETHXAUUS3"; // The set of symbols for calculation
string local_sym = Symbol(); // Current symbol, e.g., "EURUSD"
// Extract the first 3 and the last 3 characters of the symbol name
local_a = StringSubstr(local_sym, 0, 3); // Base currency
local_b = StringSubstr(local_sym, 3, 3); // Quote currency
// Find positions of each substring in local_par
local_c = StringFind(local_par, local_a, 0);
local_d = StringFind(local_par, local_b, 0);
// Calculate the magic number based on the found positions
local_i = 146411 * (local_c + 1) + local_d;
// Print the result for debugging purposes
Print("MagicNumber for ", local_a, local_b, " (", local_c, ", ", local_d, ") is: ", local_i);
return local_i;
}
// Function to check if a position is open for the current symbol
bool isPositionOpen(int magicNumber = -1) {
// Attempt to select the position for the current symbol
if (PositionSelect(Symbol())) {
// Check if a specific magic number is provided and matches
if (magicNumber != -1 && PositionGetInteger(POSITION_MAGIC) != magicNumber) {
return false; // Return false if magic number doesn't match
}
return true; // Return true if position is open with matching conditions
}
return false; // No position found for the symbol
}