Overall Statistics
Total Trades
129
Average Win
2.80%
Average Loss
-2.36%
Compounding Annual Return
200.845%
Drawdown
22.100%
Expectancy
0.266
Net Profit
44.052%
Sharpe Ratio
2.198
Loss Rate
42%
Win Rate
58%
Profit-Loss Ratio
1.19
Alpha
0.832
Beta
-0.109
Annual Standard Deviation
0.378
Annual Variance
0.143
Information Ratio
2.065
Tracking Error
0.395
Treynor Ratio
-7.592
Total Fees
$377.15
namespace QuantConnect
{
    /// <summary>
    /// Basic template algorithm simply initializes the date range and cash
    /// </summary>
    public class ForexRiskManagerExample : QCAlgorithm
    {
        List<Symbol> forexPairs = new List<Symbol>();
        Dictionary<Symbol, CrossingMovingAverages> MovingAverageCross = new Dictionary<QuantConnect.Symbol, CrossingMovingAverages>();

        private const decimal _leverage = 50m;

        // How much of the total strategy equity can be at risk as maximum in all trades.
        private const decimal _maxExposure = 0.8m;

        // How much of the total strategy equity can be at risk in a single trade.
        private const decimal _maxExposurePerTrade = 0.25m;

        // The max strategy equity proportion to put at risk in a single operation.
        private const decimal _riskPerTrade = 0.03m;

        // Smallest lot
        private LotSize _lotSize = LotSize.Mini;

        FxRiskManagment RiskManager;



        public override void Initialize()
        {
            SetStartDate(2015, 01, 01);  //Set Start Date
            SetEndDate(2015, 04, 30);    //Set End Date
            SetCash(10000);             //Set Strategy Cash
            forexPairs.Add(AddForex("EURUSD", Resolution.Minute, market: "oanda", leverage: 50).Symbol);
            forexPairs.Add(AddForex("USDJPY", Resolution.Minute, market: "oanda", leverage: 50).Symbol);

            RiskManager = new FxRiskManagment(Portfolio, _riskPerTrade, _maxExposurePerTrade, _maxExposure, _lotSize);

            foreach (var pair in forexPairs)
            {
                Securities[pair].VolatilityModel = new ThreeSigmaVolatilityModel(STD(pair, 12 * 60, Resolution.Minute));


                var fast_moving_average = new ExponentialMovingAverage(1440).Of(Identity(pair));
                var slow_moving_average = new LinearWeightedMovingAverage(1440).Of(Identity(pair));
                MovingAverageCross[pair] = new CrossingMovingAverages(fast_moving_average, slow_moving_average);
            }

            SetWarmUp(TimeSpan.FromMinutes(1440));

            SetBrokerageModel(Brokerages.BrokerageName.OandaBrokerage);
        }



        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice data)
        {
            if (IsWarmingUp) return;
            foreach (var pair in forexPairs)
            {
                if (!data.ContainsKey(pair) || !MovingAverageCross[pair].IsReady) continue;
                var signal = MovingAverageCross[pair].Signal;
                if (   signal == CrossingMovingAveragesSignals.FastCrossSlowFromAbove
                    || signal == CrossingMovingAveragesSignals.FastCrossSlowFromBelow)
                {
                    if ((Portfolio[pair].IsLong && signal == CrossingMovingAveragesSignals.FastCrossSlowFromAbove)
                        || (Portfolio[pair].IsShort && signal == CrossingMovingAveragesSignals.FastCrossSlowFromBelow))
                    {
                        Liquidate(pair);
                    }
                    else if (!Portfolio[pair].Invested)
                    {
                        var actualAction = (signal == CrossingMovingAveragesSignals.FastCrossSlowFromBelow) ? AgentAction.GoLong : AgentAction.GoShort;
                        var entryValues = RiskManager.CalculateEntryOrders(pair, actualAction);
                        if (entryValues.Item1 == 0) continue;

                        var ticket = MarketOrder(pair, entryValues.Item1);
                        StopMarketOrder(pair, -entryValues.Item1, entryValues.Item2);
                    }

                }
            }
			RiskManager.UpdateTrailingStopOrders();
        }
    }
}
namespace QuantConnect
{
    public enum CrossingMovingAveragesSignals
    {
        Bullish = 1,
        FastCrossSlowFromAbove = -2,
        Bearish = -1,
        FastCrossSlowFromBelow = 2,
    }

    public class CrossingMovingAverages
    {
        CompositeIndicator<IndicatorDataPoint> _moving_average_difference;
        public CrossingMovingAveragesSignals Signal { get; private set; }
        private bool _isReady;
        int _lastSignal;


        public bool IsReady
        {
            get { return _isReady; }
        }


        public CrossingMovingAverages(IndicatorBase<IndicatorDataPoint> fast_moving_average, IndicatorBase<IndicatorDataPoint> slow_moving_average)
        {
            _moving_average_difference = fast_moving_average.Minus(slow_moving_average);
            _moving_average_difference.Updated += ma_Updated;
        }

        private void ma_Updated(object sender, IndicatorDataPoint updated)
        {
            if (!_isReady)
            {
                _isReady = _moving_average_difference.Right.IsReady;
                return;
            }
            var actualSignal = Math.Sign(_moving_average_difference);
            if (actualSignal == _lastSignal || _lastSignal == 0)
            {
                Signal = (CrossingMovingAveragesSignals)actualSignal;
            }
            else if (_lastSignal == -1 && actualSignal == 1)
            {
                Signal = CrossingMovingAveragesSignals.FastCrossSlowFromBelow;
            }
            else if (_lastSignal == 1 && actualSignal == -1)
            {
                Signal = CrossingMovingAveragesSignals.FastCrossSlowFromAbove;
            }

            _lastSignal = actualSignal;
        }
    }
}
namespace QuantConnect
{
    public enum LotSize
    {
        Standard = 100000,
        Mini = 10000,
        Micro = 1000,
        Nano = 100,
    }
    
    public enum AgentAction
    {
        GoShort = -1,
        DoNothing = 0,
        GoLong = 1
    }

    public class FxRiskManagment
    {
        // Maximum equity proportion to put at risk in a single operation.
        private decimal _riskPerTrade;

        // Maximum equity proportion at risk in open positions in a given time.
        private decimal _maxExposure;

        // Maximum equity proportion at risk in a single trade.
        private decimal _maxExposurePerTrade;

        private int _lotSize;

        private int _minQuantity;

        private SecurityPortfolioManager _portfolio;

        /// <summary>
        /// Initializes a new instance of the <see cref="FxRiskManagment"/> class.
        /// </summary>
        /// <param name="portfolio">The QCAlgorithm Portfolio.</param>
        /// <param name="riskPerTrade">The max risk per trade.</param>
        /// <param name="maxExposurePerTrade">The maximum exposure per trade.</param>
        /// <param name="maxExposure">The maximum exposure in all trades.</param>
        /// <param name="lotsize">The minimum quantity to trade.</param>
        /// <exception cref="System.NotImplementedException">The pairs should be added to the algorithm before initialize the risk manager.</exception>
        public FxRiskManagment(SecurityPortfolioManager portfolio, decimal riskPerTrade, decimal maxExposurePerTrade,
                               decimal maxExposure, LotSize lotsize = LotSize.Micro, int minQuantity = 5)
        {
            _portfolio = portfolio;
            if (_portfolio.Securities.Count == 0)
            {
                throw new NotImplementedException("The pairs should be added to the algorithm before initialize the risk manager.");
            }
            this._riskPerTrade = riskPerTrade;
            _maxExposurePerTrade = maxExposurePerTrade;
            this._maxExposure = maxExposure;
            _lotSize = (int)lotsize;
            _minQuantity = minQuantity;
        }

        /// <summary>
        /// Calculates the entry orders and stop-loss price.
        /// </summary>
        /// <param name="pair">The Forex pair Symbol.</param>
        /// <param name="action">The order direction.</param>
        /// <returns>a Tuple with the quantity as Item1 and the stop-loss price as Item2. If quantity is zero, then means that no trade must be done.</returns>
        public Tuple<int, decimal> CalculateEntryOrders(Symbol pair, AgentAction action)
        {
            // If exposure is greater than the max exposure, then return zero.
            if (_portfolio.TotalMarginUsed > _portfolio.TotalPortfolioValue * _maxExposure)
            {
                return Tuple.Create(0, 0m);
            }
            var closePrice = _portfolio.Securities[pair].Price;
            var leverage = _portfolio.Securities[pair].Leverage;
            var exchangeRate = _portfolio.Securities[pair].QuoteCurrency.ConversionRate;
            var volatility = _portfolio.Securities[pair].VolatilityModel.Volatility;

            // Estimate the maximum entry order quantity given the risk per trade.
            var moneyAtRisk = _portfolio.TotalPortfolioValue * _riskPerTrade;
            var maxQuantitybyRisk = moneyAtRisk / (volatility * exchangeRate);
            // Estimate the maximum entry order quantity given the exposure per trade.
            var maxBuySize = Math.Min(_portfolio.MarginRemaining, _portfolio.TotalPortfolioValue * _maxExposurePerTrade) * leverage;
            var maxQuantitybyExposure = maxBuySize / (closePrice * exchangeRate);
            // The final quantity is the lowest of both.
            var quantity = (int)(Math.Round(Math.Min(maxQuantitybyRisk, maxQuantitybyExposure) / _lotSize, 0) * _lotSize);
            // If the final quantity is lower than the minimum quantity of the given lot size, then return zero.
            if (quantity < _lotSize * _minQuantity) return Tuple.Create(0, 0m);

            quantity = action == AgentAction.GoLong ? quantity : -quantity;
            var stopLossPrice = closePrice + (action == AgentAction.GoLong ? -volatility : volatility);
            return Tuple.Create(quantity, stopLossPrice);
        }

        /// <summary>
        /// Updates the stop-loss price of all open StopMarketOrders.
        /// </summary>
        public void UpdateTrailingStopOrders()
        {
            // Get all the spot-loss orders.
            var openStopLossOrders = _portfolio.Transactions.GetOrderTickets(o => o.OrderType == OrderType.StopMarket && o.Status == OrderStatus.Submitted);
            foreach (var ticket in openStopLossOrders)
            {
                var stopLossPrice = ticket.SubmitRequest.StopPrice;
                var volatility = _portfolio.Securities[ticket.Symbol].VolatilityModel.Volatility;
                var actualPrice = _portfolio.Securities[ticket.Symbol].Price;
                // The StopLossOrder has the opposite direction of the original order.
                var originalOrderDirection = ticket.Quantity > 0 ? OrderDirection.Sell : OrderDirection.Buy;
                var newStopLossPrice = actualPrice + (volatility * (originalOrderDirection == OrderDirection.Buy ? -1 : 1));
                if ((originalOrderDirection == OrderDirection.Buy && newStopLossPrice > stopLossPrice)
                    || (originalOrderDirection == OrderDirection.Sell && newStopLossPrice < stopLossPrice))
                {
                    ticket.Update(new UpdateOrderFields { StopPrice = newStopLossPrice });
                }
            }
        }
    }

}
namespace QuantConnect
{
    /// <summary>
    /// Provides an implementation of <see cref="IVolatilityModel"/> that computes the
    /// relative standard deviation as the volatility of the security
    /// </summary>
    public class ThreeSigmaVolatilityModel : IVolatilityModel
    {
        private readonly TimeSpan _periodSpan;
        private StandardDeviation _standardDeviation;

        /// <summary>
        /// Gets the volatility of the security as a percentage
        /// </summary>
        public decimal Volatility
        {
            get { return _standardDeviation * 2.5m; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QuantConnect.Securities.RelativeStandardDeviationVolatilityModel"/> class
        /// </summary>
        /// <param name="periodSpan">The time span representing one 'period' length</param>
        /// <param name="periods">The nuber of 'period' lengths to wait until updating the value</param>
        public ThreeSigmaVolatilityModel(StandardDeviation standardDeviation)
        {
            _standardDeviation = standardDeviation;
            _periodSpan = TimeSpan.FromMinutes(standardDeviation.Period);
        }

        /// <summary>
        /// Updates this model using the new price information in
        /// the specified security instance
        /// </summary>
        /// <param name="security">The security to calculate volatility for</param>
        /// <param name="data"></param>
        public void Update(Security security, BaseData data)
        {
        }

        public IEnumerable<HistoryRequest> GetHistoryRequirements(Security security, DateTime utcTime)
        {
            return Enumerable.Empty<HistoryRequest>();
        }
    }
}