// ha dentro ichimoku, medie, atr //+------------------------------------------------------------------ #property copyright "© KKxFF, 2020" //#property link "mladenfx@gmail.com" #property description "Strategy" //+------------------------------------------------------------------ #property indicator_chart_window // l'indicatore sta nella stessa finestra delle candele' #property indicator_buffers 17 // predispongo 17 buffer per i dati di memoria per l'indicatore' #property indicator_plots 9 // quante cose disegno sul grafico (linee, riempimenti...) // 3 buffer per ichimoku (due linee e riempimento) //EMA media a (50) periodi #property indicator_label1 "EMA_A" // etichetta sul grafico #property indicator_type1 DRAW_COLOR_LINE // segnalo che e' una linea' #property indicator_color1 clrDeepSkyBlue, clrDeepSkyBlue //color contiene una lista di colori che deve avere la linea. // in questo caso ha due colori nel caso per esigenze di codice lo volessimo cambiare #property indicator_style1 STYLE_SOLID // tratteggio, puntini... #property indicator_width1 2 // ampiezza //EMA #property indicator_label2 "EMA_B" #property indicator_type2 DRAW_COLOR_LINE #property indicator_color2 clrOrange, clrOrange #property indicator_style2 STYLE_SOLID #property indicator_width2 2 //Ichimoku #property indicator_label3 "Tenkan-sen" #property indicator_type3 DRAW_LINE // segnalo che e' una linea' [potrebbero essere simili] #property indicator_color3 clrNONE // colore speciale che mi permette di identificare una linea trasparente #property indicator_label4 "Kijun-sen" #property indicator_type4 DRAW_LINE #property indicator_color4 clrNONE #property indicator_label5 "Senkou Span A;Senkou Span B" #property indicator_type5 DRAW_FILLING //riempimento tra le due linee senza contorno #property indicator_color5 SandyBrown, Thistle #property indicator_label6 "Chikou Span" #property indicator_type6 DRAW_LINE #property indicator_color6 clrNONE #property indicator_label7 "Asian session High; Asian session Low" #property indicator_type7 DRAW_FILLING #property indicator_color7 MistyRose #property indicator_style7 STYLE_SOLID #property indicator_width7 1 //trigger buy #property indicator_label8 "TriggerBuy" #property indicator_type8 DRAW_COLOR_ARROW // pallini per indicare il segnale di sell e di buy #property indicator_color8 clrGreen, clrRed //verde compra, rosso vendi #property indicator_style8 STYLE_SOLID #property indicator_width8 10 // input tipoDiDato nomeVariabile = valoreIniziale // con input significa che posso modificare da GUI //EMA1 & EMA2 input int inpPeriodA = 50; // Period // mi permette di identificare il prezzo, da ora si chiamerà inpPrice // dal pdv del GUI, l'utente può decidere se prendere HLOC // dal pdv dello script, si fanno i calcoli con il dato selezionato' input ENUM_APPLIED_PRICE inpPrice = PRICE_CLOSE; // Price input int inpPeriodB = 169; // Period // buffer per tenere i dati delle due medie double valA[], valcA[]; double valB[], valcB[]; //Ichimoku input int InpTenkan = 24; // Tenkan-sen input int InpKijun = 60; // Kijun-sen input int InpSenkou = 180; // Senkou Span B input int InpCloudOffset = 40; // Cloud offset // vettori dinamici in cui lo spazio non è ancora allocato. Servono per il grafico double ExtTenkanBuffer[]; double ExtKijunBuffer[]; double ExtSpanABuffer[]; double ExtSpanBBuffer[]; double ExtChikouBuffer[]; //Asia session input int InpAsianMaxDelta = 16; // massima altezza in pips dell'asiatica //Calcolo delle medie input int lunghezzaMedia = 20; // ampiezza della media per i volumi double AsiaHigh[]; double AsiaLow[]; // Time constants are specified across Greenwich // si tiene conto anche del cambio d'ora const int AsiaOpen = 0; const int AsiaClose = 5; const int AsiaOpenSummertime = 1; // The Asian session shifts const int AsiaCloseSummertime = 7; // after the time changes // variabili temporanee per i conti dell'asiatica' int ShiftTime; //Displacement of the buffer for construction of the future sessions double HighForFutureSession; // High for the future session double LowForFutureSession; // Low for the future session //buy trigger // ushort=16bit interi senza segno input ushort code = 159; // Symbol code to draw in DRAW_ARROW double ColorArrowBuffer[]; //indica dove va posizionato il pallino double triggerColorIndex[]; // indica il colore del pallino // lavora con i double anche se sono array //signal window input string InpStartTime = "06:00"; // Do not trade before (server time)... input string InpEndTime = "16:15"; // Do not trade after (server time)... // conversione dei tempi in secondi datetime startTrading = StringToTime(InpStartTime) % 86400; //secondi in un giorno datetime stopTrading = StringToTime(InpEndTime) % 86400; //trigger buy int OnInit() //metodo che si esegue all'accensione dello script' { // int come il main di C che deve restituire 0 // IndicatorSetString permette di modificare i vari parametri // IndicatorSetString(parametroDaModificare, nuovoValore) IndicatorSetString(INDICATOR_SHORTNAME, "AsianFuckerConVolumi"); // alloco la posizione dell'indicatore nel buffer il dato corrispondente a valA' //EMA1 & EMA2 SetIndexBuffer(0, valA, INDICATOR_DATA); // valore effettivo della media SetIndexBuffer(1, valcA, INDICATOR_COLOR_INDEX); // colore che deve avere la media _emaA.init(inpPeriodA); // inizializzo con il valore inpPerdioA // stessa cosa di sopra SetIndexBuffer(2, valB, INDICATOR_DATA); SetIndexBuffer(3, valcB, INDICATOR_COLOR_INDEX); _emaB.init(inpPeriodB); //Ichimoku //--- indicator buffers mapping SetIndexBuffer(4, ExtTenkanBuffer, INDICATOR_DATA); SetIndexBuffer(5, ExtKijunBuffer, INDICATOR_DATA); SetIndexBuffer(6, ExtSpanABuffer, INDICATOR_DATA); SetIndexBuffer(7, ExtSpanBBuffer, INDICATOR_DATA); SetIndexBuffer(8, ExtChikouBuffer, INDICATOR_DATA); //--- sets first bar from what index will be drawn PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, InpTenkan); //PLOT_DRAW_BEGIN indica quanto far partire il disegno (shift per fare in modo... //... che sia disegnabile rispettando il numero di elementi) PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, InpKijun); PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, InpSenkou - 1); //--- lines shifts when drawing PlotIndexSetInteger(4, PLOT_SHIFT, InpCloudOffset); //PLOT_SHIFT shifto esattamente PlotIndexSetInteger(5, PLOT_SHIFT, -InpKijun); // tiro indietro il grafico //--h- change labels for DataWindow PlotIndexSetString(2, PLOT_LABEL, "Tenkan-sen(" + string(InpTenkan) + ")"); //PLOT_LABEL sovrascrive l'etichetta prima dichiarata' PlotIndexSetString(3, PLOT_LABEL, "Kijun-sen(" + string(InpKijun) + ")"); PlotIndexSetString(4, PLOT_LABEL, "Senkou Span A;Senkou Span B(" + string(InpSenkou) + ")"); //asian range //--- Verify Time Period if (PeriodSeconds(_Period) >= PeriodSeconds(PERIOD_H2)) { return (-1); } //--- Displacement of the buffer for construction of the future sessions ShiftTime = PeriodSeconds(PERIOD_D1) / PeriodSeconds(_Period); // quanti secondi in una giornata / quanti secondi nel periodo che usiamo adesso // se sono in h1 ho una shift time di 24candele, una all'ora. La 24esima, partendo il vettore da 0 corrisponde alla prima ora del secondo giorno // con m5 sono 288 candele //--- indicators SetIndexBuffer(9, AsiaHigh, INDICATOR_DATA); SetIndexBuffer(10, AsiaLow, INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //trigger //--- indicator buffers mapping SetIndexBuffer(11, ColorArrowBuffer, INDICATOR_DATA); //--- Define the symbol code for drawing in PLOT_ARROW PlotIndexSetInteger(11, PLOT_ARROW, code); //--- Set the vertical shift of arrows in pixels PlotIndexSetInteger(11, PLOT_ARROW_SHIFT, 5); //--- Set as an empty value 0 PlotIndexSetDouble(11, PLOT_EMPTY_VALUE, 0); SetIndexBuffer(12, triggerColorIndex, INDICATOR_COLOR_INDEX); return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| get highest value for range | //+------------------------------------------------------------------+ double Highest(const double &array[], int range, int fromIndex) { double res = 0; //--- res = array[fromIndex]; for (int i = fromIndex; i > fromIndex - range && i >= 0; i--) { if (res < array[i]) res = array[i]; } //--- return (res); } //+------------------------------------------------------------------+ //| get lowest value for range | //+------------------------------------------------------------------+ double Lowest(const double &array[], int range, int fromIndex) { double res = 0; //--- res = array[fromIndex]; for (int i = fromIndex; i > fromIndex - range && i >= 0; i--) { if (res > array[i]) res = array[i]; } //--- return (res); } int OnCalculate(const int rates_total, // indica le lunghezza dei vettori che seguono const int prev_calculated, // per tenere il conto del punto di partenza del calcolo degli indicatori const datetime &time[], // time[i] indica il momento di apertura della candela. // la candela piu' recente e' quella a cui ci si riferisce con [rates_total-1], quella più vecchia e' time[0]' const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], // indica la quantita' di denaro spostata' const long &volume[], // per il momento non lo usiamo const int &spread[]) // differenza tra valore di buy e sell { //medie e Ichimoku int i = prev_calculated - 1; if (i < 0) { i = 0; } // se i è minore di 0, lo setto a 0, e poi procedo, altrimenti procedo direttamente for (; i < rates_total && !_StopFlag; i++) { // nessuna condizione di partenza, solo arresto e aggiornamento // _StopFlag è una variabile d'ambiente (posso interagire mentre si esegue il codice da GUI) valA[i] = _emaA.calculate(getPrice(inpPrice, open, high, low, close, i), i, rates_total); //valore emaA valcA[i] = 0; // prendo il primo colore dei vettori di A di quelli prima definiti con property valB[i] = _emaB.calculate(getPrice(inpPrice, open, high, low, close, i), i, rates_total); //valore emaB valcB[i] = 0; // prendo il primo colore dei vettori di B di quelli prima definiti con property // calcolo di ichimoku ExtChikouBuffer[i] = close[i]; //--- tenkan sen double _high = Highest(high, InpTenkan, i); double _low = Lowest(low, InpTenkan, i); ExtTenkanBuffer[i] = (_high + _low) / 2.0; //--- kijun sen _high = Highest(high, InpKijun, i); _low = Lowest(low, InpKijun, i); ExtKijunBuffer[i] = (_high + _low) / 2.0; //--- senkou span a ExtSpanABuffer[i] = (ExtTenkanBuffer[i] + ExtKijunBuffer[i]) / 2.0; //--- senkou span b _high = Highest(high, InpSenkou, i); _low = Lowest(low, InpSenkou, i); ExtSpanBBuffer[i] = (_high + _low) / 2.0; } //max e min sessione asiatica HighForFutureSession = MathMax(high[rates_total - 1], high[rates_total - 2]); // ?? come aggiorna il massimo? prendo il massimo considerando anche l'ombra della candela (high) LowForFutureSession = MathMin(low[rates_total - 1], low[rates_total - 2]); MqlDateTime time1, time2; //contiene data e orario //--- set position for beginning if (prev_calculated == 0) // è la prima volta che eseguo il metodo on calculate: non ci sono candele precedentemente calcolate { i = ShiftTime + 1; //mi sposto di un giorno in avanti ArrayInitialize(AsiaHigh, 0.0); //inizializzo esplicitamente l'array dinamico ArrayInitialize(AsiaLow, 0.0); } else i = prev_calculated - ShiftTime; // vado indietro di un giorno //--- elaboro le timezone (sessione asiatica) per ogni giorno while (i < rates_total) { TimeToStruct(time[i - 1], time1); //conversione del tipo di variabile da time[i-1] che è di tipo datetime a MqlDateTime che è una struct // time1=time[i-1]; ma con cast esplicito TimeToStruct(time[i], time2); //idem come sopra if (time1.day != time2.day) //se la variabile day dell'elemento MqlDateTime time1 e di time2 sono diverse => cambio di giorno { DrawTimeZone(time[i], i); // funzione che disegna il blocco dell'asiatica } i++; } //trigger buy & sell bool asianUnderMaxDelta = false; bool medieBuy = false; bool ichBuy = false; bool asianTopBreakout = false; bool medieSell = false; bool ichSell = false; bool asianBottomBreakout = false; bool medieFavore = false; i = 0; datetime barTime; for (; i < rates_total && !_StopFlag; i++) { barTime = time[i] + TimeGMTOffset(); //filtro candele dalle 06:00 alle 16:15 per evitare problemi con ora legale if (barTime % 86400 >= startTrading && barTime % 86400 <= stopTrading) { double highLevelAsianOfDay = getHighLevelAsianByDay(time[i]); double lowLevelAsianOfDay = getLowLevelAsianByDay(time[i]); double asianDelta = (highLevelAsianOfDay - lowLevelAsianOfDay) / (_Point * 10); //_Point*10 = 1 pip ma siccome il pip può essere la quarta o la terza o un'altra cifra decimale, parto dall'ultima e moltiplico per 10: 0.001 asianUnderMaxDelta = asianDelta < InpAsianMaxDelta; // setto a true asianUnderMaxDelta // calcolo della media double mediaVolumi = 0; // dichiaro la variabile di tipo double // calcolo delle medie if (i > lunghezzaMedia + 1) // altrimenti non posso calcolarla { for (int x = i - mediaVolumi; x < i; x = x + 1) // lunghezzaMedia è definita sopra come property { mediaVolumi = mediaVolumi + tick_volume[x]; } mediaVolumi = mediaVolumi / lunghezzaMedia; // trigger medie medieFavore = mediaVolumi < tick_volume[i]; } //trigger buy medieBuy = valA[i] > valB[i] && open[i] < close[i] && open[i] >= valA[i]; ichBuy = ExtSpanABuffer[i] > ExtSpanBBuffer[i]; asianTopBreakout = open[i] <= highLevelAsianOfDay && close[i] > highLevelAsianOfDay; if (medieBuy && ichBuy && asianTopBreakout && medieFavore) { ColorArrowBuffer[i] = low[i] - (_Point * 10 * 2); triggerColorIndex[i] = 0; } //trigger sell medieSell = valA[i] < valB[i] && open[i] > close[i] && open[i] <= valA[i]; ichSell = ExtSpanABuffer[i] < ExtSpanBBuffer[i]; asianBottomBreakout = open[i] >= lowLevelAsianOfDay && close[i] < lowLevelAsianOfDay; if (medieSell && ichSell && asianBottomBreakout && medieFavore) { ColorArrowBuffer[i] = high[i] + (_Point * 10 * 2); triggerColorIndex[i] = 1; } } } return (rates_total); } class CEma //nome della classe { private: //attributi o metodi privati double m_period; double m_alpha; double m_array[]; int m_arraySize; public: // attributi o metodi pubblici CEma() : m_period(1), m_alpha(1), m_arraySize(-1) { return; } // costruttore HA LO STESSO NOME DELLA CLASSE // le istruzioni inizializzano le variabili della classe quando viene chiamato il costruttore ~CEma() { return; } // distruttore void init(int period) // in base al periodo calcola altri parametri { m_period = (period > 1) ? period : 1; m_alpha = 2.0 / (1.0 + m_period); // peso della media (?) } double calculate(double value, int i, int bars) // calcola il valore della media quando ho una nuova candela { if (m_arraySize < bars) { m_arraySize = ArrayResize(m_array, bars + 500); if (m_arraySize < bars) return (0); } if (i > 0) m_array[i] = m_array[i - 1] + m_alpha * (value - m_array[i - 1]); else m_array[i] = value; return (m_array[i]); } }; // dichiaro due oggetti di classe ema CEma _emaA; CEma _emaB; template double getPrice(ENUM_APPLIED_PRICE tprice, T &open[], T &high[], T &low[], T &close[], int i) { switch (tprice) { case PRICE_CLOSE: return (close[i]); case PRICE_OPEN: return (open[i]); case PRICE_HIGH: return (high[i]); case PRICE_LOW: return (low[i]); case PRICE_MEDIAN: return ((high[i] + low[i]) / 2.0); case PRICE_TYPICAL: return ((high[i] + low[i] + close[i]) / 3.0); case PRICE_WEIGHTED: return ((high[i] + low[i] + close[i] + close[i]) / 4.0); } return (0); } //------------------------------------------------------------------ //+--------------------------------------------------------------------+ // Summertime determination is reserved for the future calculations //+--------------------------------------------------------------------+ bool Summertime(datetime time) { if (TimeDaylightSavings() != 0) return (true); else return (false); } //+--------------------------------------------------------------------+ // Calculation and filling of buffers of time zones //+--------------------------------------------------------------------+ void DrawTimeZone(datetime Start, int Index) // disegna il blocchetto per ogni sessione, noi lo usiamo per l'asiatica { int rates_total, shift, shift_end, _startIndex = Index; double iHigh[], iLow[], HighSession, LowSession; // dichiaro qui i vettori iHIgh e iLOw che manterranno tutti i valori assunti da High e Low nella sessione nel pair nel periodo... datetime AsiaStart, AsiaEnd; datetime _start = Start + (TimeTradeServer() - TimeGMT()); // DISEGNO DEL RETTANGOLO / DESTRA E SINISTRA // Processing of the Asian session //AsiaStart e AsiaEnd indicano l'inizio e la fine dell'asiatica AsiaStart = _start + (Summertime(Start) ? AsiaOpenSummertime : AsiaOpen) * PeriodSeconds(PERIOD_H1); AsiaEnd = _start + (Summertime(Start) ? AsiaCloseSummertime : AsiaClose) * PeriodSeconds(PERIOD_H1) - 1; // condizione? se true: false // se summertime(Start) è vero, allora assegno AsiaOpenSummerTime, altirmenti AsiaOpen // Summertime verifica se c'è o meno l'ora legale // DISEGNO DEL RETTANGOLO / SOPRA E SOTTO rates_total = CopyHigh(NULL, _Period, AsiaStart, AsiaEnd, iHigh); // NULL indica pair su cui si sta lavorando, se voglio tenerne quella selezionata dò null // _Period è una variabile d'ambiente e fa riferimento al periodo su cui è inserito l'indicatore // AsiaStart e AsiaEnd è il periodo dell'asiatica // iHigh è un vettore nostro in cui salviamo i valori degli spike positivi del pair selezionato nella sessione asiatica corrispondente // CopyHigh mette in iHigh e restituisce il numero di candele messe in iHigh, che è la lunghezza di quel vettore. In questo caso ratesTotal assume questo valore if (rates_total <= 0) // torna -1 in caso di errore (forse questo accade quando c'è la sessione asiatica) HighSession = HighForFutureSession; else // quando la sessione asiatica è fatta HighSession = iHigh[ArrayMaximum(iHigh, 0, rates_total)]; //ArrayMaximum(vettore, indice di partenza, indice di fine) TORNA L'INDICE, NON IL VALORE // fa lo stesso con il low rates_total = CopyLow(NULL, _Period, AsiaStart, AsiaEnd, iLow); if (rates_total <= 0) LowSession = LowForFutureSession; else LowSession = iLow[ArrayMinimum(iLow, 0, rates_total)]; // trovo gli indici delle candele di dove inizia l'asiatica e dove finisce shift = int((AsiaStart - Start) / PeriodSeconds(_Period)); shift_end = int((AsiaEnd - Start) / PeriodSeconds(_Period) + 1); // definisco le due linee alto e basso for (int i = shift; i < shift_end; i++) { AsiaHigh[_startIndex + i] = HighSession; AsiaLow[_startIndex + i] = LowSession; } // Memory clearing ArrayResize(iHigh, 0); ArrayResize(iLow, 0); } double getHighLevelAsianByDay(datetime barTime) { MqlDateTime barTimeStruct; TimeToStruct(barTime, barTimeStruct); barTimeStruct.hour = 0; barTimeStruct.min = 0; datetime offset = StructToTime(barTimeStruct); datetime _start = offset + (TimeTradeServer() - TimeGMT()); datetime AsiaStart = _start + (Summertime(offset) ? AsiaOpenSummertime : AsiaOpen) * PeriodSeconds(PERIOD_H1); datetime AsiaEnd = _start + (Summertime(offset) ? AsiaCloseSummertime : AsiaClose) * PeriodSeconds(PERIOD_H1) - 1; double barsHigh[]; int rates_total = CopyHigh(NULL, _Period, AsiaStart, AsiaEnd, barsHigh); int maximumIndex = ArrayMaximum(barsHigh, 0, rates_total); double MaximumOfSession = barsHigh[maximumIndex]; // Memory clearing ArrayResize(barsHigh, 0); return MaximumOfSession; } double getLowLevelAsianByDay(datetime barTime) { MqlDateTime barTimeStruct; TimeToStruct(barTime, barTimeStruct); barTimeStruct.hour = 0; barTimeStruct.min = 0; datetime offset = StructToTime(barTimeStruct); datetime _start = offset + (TimeTradeServer() - TimeGMT()); datetime AsiaStart = _start + (Summertime(offset) ? AsiaOpenSummertime : AsiaOpen) * PeriodSeconds(PERIOD_H1); datetime AsiaEnd = _start + (Summertime(offset) ? AsiaCloseSummertime : AsiaClose) * PeriodSeconds(PERIOD_H1) - 1; double barsLow[]; int rates_total = CopyLow(NULL, _Period, AsiaStart, AsiaEnd, barsLow); int minimumIndex = ArrayMinimum(barsLow, 0, rates_total); double MinimumOfSession = barsLow[minimumIndex]; // Memory clearing ArrayResize(barsLow, 0); return MinimumOfSession; }