Example of a Moving Average Crossover strategy

using System;
using System.Collections.Generic;
using System.Linq;
using TSLab.Script;
using TSLab.Script.Handlers;
using TSLab.Script.Helpers;
using TSLab.Script.Optimization;

namespace MyLib
{
    public class CrossMA : IExternalScript
    {
        // Optimization Options
        public OptimProperty PeriodFast = new OptimProperty(10, 10, 50, 5);
        public OptimProperty PeriodSlow = new OptimProperty(50, 50, 200, 10);

        // Processing method, launched when recounting the script
        public virtual void Execute(IContext ctx, ISecurity sec)
        {
            // Compute Fast and Slow SMA
            // We use GetData for data caching and acceleration of optimization
            var smaSlow = ctx.GetData("SMA", new[] { PeriodSlow.ToString() },
                () => Series.SMA(sec.GetClosePrices(ctx), PeriodSlow));
            var smaFast = ctx.GetData("SMA", new[] { PeriodFast.ToString() },
                () => Series.SMA(sec.GetClosePrices(ctx), PeriodFast));

            // If the last candlestick is not fully formed, it does not need to be used in the trading cycle.
            var barsCount = sec.Bars.Count;
            if (!ctx.IsLastBarUsed)
            {
                barsCount--;
            }

            var startBar = Math.Max(PeriodSlow, ctx.TradeFromBar);

            // Trade
            for (int i = startBar; i < barsCount; i++)
            {
                // We calculate signals
                var sLong = smaFast[i] > smaSlow[i] && smaFast[i - 1] <= smaSlow[i - 1];
                var sShort = smaFast[i] < smaSlow[i] && smaFast[i - 1] >= smaSlow[i - 1];

                // Get Active Positions
                var posLong = sec.Positions.GetLastActiveForSignal("LE", i);
                var posShort = sec.Positions.GetLastActiveForSignal("SE", i);

                if (posLong == null)
                {
                    // If there is no active long position and there is a buy signal, then we buy according to the market
                    if (sLong)
                    {
                        sec.Positions.BuyAtMarket(i + 1, 1, "LE");
                    }
                }
                else
                {
                    // If there is a long position and there is a sell signal, then close the long market
                    if (sShort)
                    {
                        posLong.CloseAtMarket(i + 1, "LX");
                    }
                }


                if (posShort == null)
                {
                    // If there is no active short position and there is a sell signal, then we sell according to the market
                    if (sShort)
                    {
                        sec.Positions.SellAtMarket(i + 1, 1, "SE");
                    }
                }
                else
                {
                    // If there is a short position and there is a buy signal, then close the market short
                    if (sLong)
                    {
                        posShort.CloseAtMarket(i + 1, "SX");
                    }
                }
            }

            // If the optimization process is ongoing, then you do not need to draw graphics, this slows down the work
            if (ctx.IsOptimization)
            {
                return;
            }

            // Drawing graphs
            ctx.First.AddList(string.Format("SMAFast({0})", PeriodFast), smaFast, ListStyles.LINE, ScriptColors.Green,
                LineStyles.SOLID, PaneSides.RIGHT);
            ctx.First.AddList(string.Format("SMASlow({0})", PeriodSlow), smaSlow, ListStyles.LINE, ScriptColors.Red,
                LineStyles.SOLID, PaneSides.RIGHT);
        }
    }
}

Last updated