Overall Statistics
Total Trades
8
Average Win
0.47%
Average Loss
0%
Compounding Annual Return
-33.408%
Drawdown
4.100%
Expectancy
0
Net Profit
-1.724%
Sharpe Ratio
-2.724
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
-0.332
Beta
0.282
Annual Standard Deviation
0.121
Annual Variance
0.015
Information Ratio
-2.661
Tracking Error
0.126
Treynor Ratio
-1.171
Total Fees
$8.00
//Copyright HardingSoftware.com 2019, granted to the public domain.
//Use at your own risk. Do not remove this copyright notice.
namespace QuantConnect.Algorithm.CSharp
{
    public class TMA2Algo : QCAlgorithm
    {
		//Symbol symbol = QuantConnect.Symbol.Create("Y", SecurityType.Equity, Market.USA);
		int period = 10;
		decimal LimitRatio = 0.5m;
		Resolution resolution = Resolution.Minute;
		TimeSpan orderExpiryTime = new TimeSpan(0,0,0,59);
		int priceDecimals = 2;
		List<TradeBar> history = new List<TradeBar>();
		decimal startCash = 5000;
		
        public override void Initialize()
        {
            SetStartDate(2018, 8, 26);
            SetEndDate(2019, 8, 26);
            SetCash(startCash);
            
            //AddEquity(symbol, resolution);
            AddUniverse(CoarseSelectionFilter);
            UniverseSettings.Resolution = Resolution.Minute;
            UniverseSettings.Leverage = 2;
            AddRiskManagement(new MaximumDrawdownPercentPerSecurity());
        }
        
        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
        	Log($"OnSecuritiesChanged({UtcTime}):: {changes}");
        	
  /*      	foreach (var security in changes.RemovedSecurities)
    		{
    			if (security.Invested)
    			{
    				Liquidate(security.Symbol);
    			}
    		}
  */  		
    		//2. Now that we have more leverage, set the allocation to set the allocation to 18% each instead of 10%
    		foreach (var security in changes.AddedSecurities)
    		{
    			SetHoldings(security.Symbol, 0.18m);
    		}
        }
        
        public IEnumerable<Symbol> CoarseSelectionFilter(IEnumerable<CoarseFundamental> coarse)
        {	
        	var sortedByDollarVolume = coarse.OrderByDescending(x => x.DollarVolume);
        	var filteredByPrice = sortedByDollarVolume.Where(x => x.Price > 10).Select(x => x.Symbol);
        	filteredByPrice = filteredByPrice.Take(10);
        	return filteredByPrice;
        }

        public override void OnData(Slice data)
        {
        	CancelExpiredOrders();
        	foreach(var kvp in Securities)
        	{
        		var symbol = kvp.Key;
        		
	        	if (data.Bars.ContainsKey(symbol) && data.Bars[symbol] != null)
	        	{
	        		history.Add(data.Bars[symbol]);
	        		if (history.Count > period)
	        		{
	        			history.RemoveAt(0);
	        		}
	        		else
	        		{
	        			return;
	        		}
	                decimal tma = TMA2.TriangularCandleAverage(history);
	                decimal range = TMA2.FullRange(history);
	                decimal buyPrice = tma - LimitRatio * range;
	                decimal sellPrice = tma + LimitRatio * range;
	    			if (Portfolio[symbol].Quantity == 0)
	    			{
	    				buyPrice = Math.Round(buyPrice, priceDecimals);
	    				if (buyPrice > 0)
	    				{
		    				decimal quantity = startCash / buyPrice;
		    				if (OrderIsPlaced(symbol, quantity) == false)
		    				{
		    					Transactions.CancelOpenOrders();
		        				LimitOrder(symbol, quantity, buyPrice);
		    				}
	    				}
	    			}
	    			else if (Portfolio[symbol].Quantity > 0)
	    			{
	    				sellPrice = Math.Round(sellPrice, priceDecimals);
	    				if (sellPrice > 0)
	    				{
		    				decimal quantity = -Portfolio[symbol].Quantity;
		    				if (OrderIsPlaced(symbol, quantity) == false)
		    				{
		    					Transactions.CancelOpenOrders();
		        				LimitOrder(symbol, quantity, sellPrice);
		    				}
	    				}
	    			}
	        	}
        	}
        }
        
        public bool OrderIsPlaced(Symbol symbol, decimal quantity)
        {
        	List<Order> orders = Transactions.GetOpenOrders(symbol);
        	foreach (Order order in orders)
        	{
        		if (order.Symbol == symbol)
        		{
        			if (Math.Sign(quantity) == Math.Sign(order.Quantity))
        			{
        				return true;
        			}
        		}
        	}
        	return false;
        }
        
        public void CancelExpiredOrders()
        {
        	List<Order> orders = Transactions.GetOpenOrders();
        	foreach (Order order in orders)
        	{
        		if (Time > order.Time + orderExpiryTime)
        		{
        			Transactions.CancelOrder(order.Id);
        		}
        	}
        }

		public class TMA2
		{
			//Copyright HardingSoftware.com 2019, granted to the public domain.
			//Use at your own risk. Do not remove this copyright notice.
			
			public static decimal TriangularCandleAverage(List<TradeBar> candles)
	        {
	            return TriangularMovingAverage(CandleAverages(candles));
	        }
	
	        public static decimal[] CandleAverages(List<TradeBar> candles)
	        {
	            return candles.Select(x => CandleAverage(x)).ToArray();
	        }
	
	        public static decimal CandleAverage(TradeBar candle)
	        {
	            return (candle.Open + candle.High + candle.Low + candle.Close) / 4;
	        }
	        
	        public static decimal[] TriangularWeightsDecimal(int length)
	        {
	            int[] intWeights = Enumerable.Range(1, length).ToArray();
	            return intWeights.Select(x => Convert.ToDecimal(x)).ToArray();
	        }
	
	        public static decimal TriangularMovingAverage(decimal[] values)
	        {
	            return WeightedAverage(values, TriangularWeightsDecimal(values.Length));
	        }
	        
	        public static decimal FullRange(List<TradeBar> candles)
	        {
	            return candles.Select(x => x.High).Max() - candles.Select(x => x.Low).Min();
	        }
	        
	        public static decimal WeightedAverage(decimal[] values, decimal[] weights)
	        {
	            return values.Zip(weights, (x, y) => x * y).Sum() / weights.Sum();
	        }
		}
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Portfolio;

namespace QuantConnect.Algorithm.Framework.Risk
{
    /// <summary>
    /// Provides an implementation of <see cref="IRiskManagementModel"/> that limits the drawdown
    /// per holding to the specified percentage
    /// </summary>
    public class MaximumDrawdownPercentPerSecurity : RiskManagementModel
    {
        private readonly decimal _maximumDrawdownPercent;

        /// <summary>
        /// Initializes a new instance of the <see cref="MaximumDrawdownPercentPerSecurity"/> class
        /// </summary>
        /// <param name="maximumDrawdownPercent">The maximum percentage drawdown allowed for any single security holding,
        /// defaults to 5% drawdown per security</param>
        public MaximumDrawdownPercentPerSecurity(
            decimal maximumDrawdownPercent = 0.05m
            )
        {
            _maximumDrawdownPercent = -Math.Abs(maximumDrawdownPercent);
        }

        /// <summary>
        /// Manages the algorithm's risk at each time step
        /// </summary>
        /// <param name="algorithm">The algorithm instance</param>
        /// <param name="targets">The current portfolio targets to be assessed for risk</param>
        public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
        {
            foreach (var kvp in algorithm.Securities)
            {
                var security = kvp.Value;

                if (!security.Invested)
                {
                    continue;
                }

                var pnl = security.Holdings.UnrealizedProfitPercent;
                if (pnl > (-_maximumDrawdownPercent)-0.02m)
                {
                    // liquidate
                    yield return new PortfolioTarget(security.Symbol, 0);
                }
            }
        }
    }
}