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); } } } } }