Overall Statistics
Total Trades
4
Average Win
1.32%
Average Loss
-1.46%
Compounding Annual Return
-17.440%
Drawdown
2.600%
Expectancy
-0.048
Net Profit
-0.158%
Sharpe Ratio
-0.485
Loss Rate
50%
Win Rate
50%
Profit-Loss Ratio
0.90
Alpha
0
Beta
-8.432
Annual Standard Deviation
0.18
Annual Variance
0.032
Information Ratio
-0.543
Tracking Error
0.18
Treynor Ratio
0.01
Total Fees
$46.24
using QuantConnect.Brokerages;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace QuantConnect.Algorithm.CSharp
{

    public class TestForexAlgorithm : QCAlgorithm
    {
        private string currencyPair = "EURUSD";
        private Resolution algoResolution = Resolution.Minute;
        private decimal minPriceVariation;
        private decimal leverage = 15m;
        private decimal orderSize = 0m;

        private decimal initCashSize = 25000;

        private int pipTarget = 10;
        private int pipStopLoss = 15;
        private decimal price;
        private decimal targetPrice;
        private decimal stopLossPrice;
        private int longShortDirection;

        private Dictionary<Symbol, RelativeStrengthIndex> _rsi = new Dictionary<Symbol, RelativeStrengthIndex>();
        private Dictionary<Symbol, Stochastic> _sto = new Dictionary<Symbol, Stochastic>();

        // first set of criteria
        private int stoOverbought = 80;
        private int stoOversold = 20;

        private int rsiOverbought = 70;
        private int rsiOversold = 30;

        // second set of criteria
        private RelativeStrengthIndex rsi;
        private Stochastic sto;

        private QuoteBarConsolidator fifteenMinuteConsolidator;

        public override void Initialize()
        {
            // TODO: Determine a way to exit the algo in case that during init it is found that the account carries equities
            if (Portfolio.HoldStock)
            {
                Log("The Portfolio is not empty!");

            }

            SetStartDate(2013, 1, 7);
            SetEndDate(2013, 1, 9);

            SetCash(initCashSize);

            AddForex(currencyPair, algoResolution, Market.FXCM);
            fifteenMinuteConsolidator = new QuoteBarConsolidator(TimeSpan.FromMinutes(15));

            rsi = new RelativeStrengthIndex("RSI_" + currencyPair, 14, MovingAverageType.Simple);
            sto = new Stochastic("STO_" + currencyPair, 14, 5, 3);

            _rsi.Add(currencyPair, rsi);
            _sto.Add(currencyPair, sto);

            RegisterIndicator(currencyPair, rsi, fifteenMinuteConsolidator);
            RegisterIndicator(currencyPair, sto, fifteenMinuteConsolidator);

            SetWarmup(20);

            SubscriptionManager.AddConsolidator(currencyPair, fifteenMinuteConsolidator);

            fifteenMinuteConsolidator.DataConsolidated += FifteenMinuteHandler;

            minPriceVariation = Securities[currencyPair].SymbolProperties.MinimumPriceVariation * 10;
            Log("Minimum Price Variation: " + minPriceVariation);

            SetBrokerageModel(BrokerageName.FxcmBrokerage);
        }

        private void FifteenMinuteHandler(object sender, QuoteBar bar)
        {
            if (_rsi.Values.All(x => x.IsReady) && _sto.Values.All(x => x.IsReady))
            {
                price = Securities[currencyPair].Price;

                if (!Portfolio.HoldStock)
                {
                    scanForEntry();
                }
                else
                {
                    scanForExit(price);
                }
            }
        }

        public void OnData(QuoteBars data)
        {
            if (rsi.IsReady)
            {
                var tmpRsi = rsi;
                tmpRsi.Update(Time , price);
                tmpRsi.Reset();

            }
        }

        private void scanForEntry()
        {
            if (_rsi[currencyPair] < rsiOversold && _sto[currencyPair].StochK < stoOversold)
            {
                longShortDirection = 1;
                orderSize = leverage * longShortDirection;

                SetHoldings(currencyPair, orderSize);
                calculateTargetAndStopLoss(pipTarget, pipStopLoss, Portfolio[currencyPair].AveragePrice, longShortDirection);
                return;
            }
            else if (_rsi[currencyPair] > rsiOverbought && _sto[currencyPair].StochK > stoOverbought)
            {
                longShortDirection = -1;
                orderSize = leverage * longShortDirection;

                SetHoldings(currencyPair, orderSize);
                calculateTargetAndStopLoss(pipTarget, pipStopLoss, Portfolio[currencyPair].AveragePrice, longShortDirection);
                return;
            }
        }

        private void calculateTargetAndStopLoss(decimal _pipTarget, decimal _pipStopLoss, decimal _averagePrice, int _longShortDirection)
        {
            targetPrice = _averagePrice + _pipTarget * minPriceVariation * _longShortDirection;
            stopLossPrice = _averagePrice + _pipStopLoss * minPriceVariation * _longShortDirection;
        }

        private void scanForExit(decimal currentPrice)
        {
            if (reachedProfitTarget(currentPrice))
            {
                Liquidate();
                Log("|Profit");
            }
            else if (reachedStopLossTarget(currentPrice))
            {
                Liquidate();
                Log("|Loss");
            }
        }

        private bool reachedProfitTarget(decimal currentPrice)
        {
            if (longShortDirection == 1)
            {
                if (currentPrice >= targetPrice)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (longShortDirection == -1)
            {
                if (currentPrice <= targetPrice)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        private bool reachedStopLossTarget(decimal currentPrice)
        {
            if (longShortDirection == 1)
            {
                if (stopLossPrice >= currentPrice)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if (longShortDirection == -1)
            {
                if (stopLossPrice <= currentPrice)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }
}