Ciao, oggi ti parlo di una delle strategie più semplici che ci siano, ovvero l’intersezione di due Medie Mobili Esponenziali (EMA).

Ciao sono Drilon e sono un programmatore con la passione per la finanza personale, questo è il mio blog dove racconto il mio percorso.

Idea di base

L’idea di base della strategia è quella di aprire un ordine BUY quando l’ema a breve termine va sopra l’ema a lungo termine, aprire un ordine SEL quando l’ema a breve termine va sotto l’ema a lungo termine.

All’apertura di un ordine si chiude l’ordine nel verso opposto!

Processo

Partendo dall’ottimizzazione dei parametri in un periodo che va dal 2019 al 2023 trovo le migliori combinazioni in questo lasso di tempo. Dopodiché la testo in un range più ampio che va dal 2011 al 2023.

Se in entrambe le situazioni la strategia si comporta bene ed ha un andamento che reputo valido a quel punto la metto in live.

Ottimizzazione

Ottimizzazione

Questo è quello che ho ottenuto dall’ottimizzazione, un andamento abbastanza costante.

L’ottimizzazione l’ho fatta sul timeframe, e le lunghezze delle due ema. Volendo si può mettere un filtro temporale sulle ore e vedere in che range di tempo conviene operare (Next step).

Backtest

backtest

Questo è il risultato del backtest dal 2011 al 2023! Non è male un 35% di profitto (ho aumentato i lotti rispetto all’ottimizzazione)

Non ha nemmeno un drawdown eccessivo però l’andamento non mi convince, non è costante. Si nota che nei primi 90 ordini non si comporta bene.
Il prossimo step sarebbe quello di andare a vedere il grafico e vedere cosa è successo in quei 90 ordini.

In questo modo possiamo trovare qualcosa per migliorare la strategia.

Conclusione

Personalmente non è una strategia che mi convince e che metterei in live, ci si può lavorare però per com’è ora assolutamente no. Il problema è che il mercato ovviamente non si comporta sempre allo stesso modo, quindi è veramente difficile trovare un setup di medie mobili che funzioni sempre.

Codice

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class IIScalping : Robot
    {

        [Parameter("Source", Group = "Data series")]
        public DataSeries Source { get; set; }

        [Parameter(DefaultValue = 100000)]
        public double takeProfit { get; set; }

        [Parameter(DefaultValue = 100000)]
        public double stopLoss { get; set; }

        [Parameter(DefaultValue = 60)]
        public int fastPeriod { get; set; }

        [Parameter(DefaultValue = 240)]
        public int slowPeriod { get; set; }

        [Parameter(DefaultValue = 0.01)]
        public double lots { get; set; }

        [Parameter(DefaultValue = 1)]
        public int maxOrder { get; set; }

        private ExponentialMovingAverage emaFast;
        private ExponentialMovingAverage emaSlow;

        protected override void OnBar()
        {
            // Put your core logic here
            emaFast = Indicators.ExponentialMovingAverage(Source, fastPeriod);
            emaSlow = Indicators.ExponentialMovingAverage(Source, slowPeriod);
            
            
            int currentBar = Bars.Count - 1;
            var positions = Positions.FindAll("Order");
      
                

                if (emaFast.Result.LastValue > emaSlow.Result.LastValue)
                {
                    Close(TradeType.Sell);
                    Open(TradeType.Buy, lots);
                }

                if (emaFast.Result.LastValue < emaSlow.Result.LastValue)
                {
                    Close(TradeType.Buy);
                    Open(TradeType.Sell, lots);
                }

        }

        private void Close(TradeType tradeType)
        {
            foreach (var position in Positions.FindAll("Order", SymbolName, tradeType))
                ClosePosition(position);
        }

        private void Open(TradeType tradeType, double lots)
        {
            var position = Positions.FindAll("Order", SymbolName, tradeType);
            var volumeInUnits = Symbol.QuantityToVolumeInUnits(lots);
            if (position == null || position.Length < maxOrder)
                ExecuteMarketOrder(tradeType, SymbolName, (double)volumeInUnits, "Order", stopLoss, takeProfit);
        }
    }
}

Parametri:

  • takeProfit: 10000 (non si utilizza)
  • stopLoss: 10000 (non si utilizza)
  • fastPeriod: 65
  • slowPeriod: 34
  • maxOrder: 1 (ordini aperti contemporaneamente)