Overall Statistics |
Total Trades 24 Average Win 0.09% Average Loss -0.02% Compounding Annual Return -17.276% Drawdown 0.200% Expectancy -0.135 Net Profit -0.035% Sharpe Ratio 0 Loss Rate 83% Win Rate 17% Profit-Loss Ratio 4.19 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $27.16 |
using System.Collections.Generic; using NodaTime; using QuantConnect.Data; using QuantConnect.Data.Custom; namespace QuantConnect.Algorithm.Examples { public enum TradingState { OutOfMarket = 0, PendingOrderEnter = 1, PendingOrderEnterCancelationSent = 2, PendingOrderExit = 3, PendingOrderExitCancelationSent = 4, InMarket = 5 }; public class Arbitrator : QCAlgorithm { bool printNextBar = false; decimal BiDirectionalIBFees = 0; decimal entryPortfolioValue = 0; decimal myCurrentSpread=0; decimal minGain = 0.3m; // not used decimal PortfolioInvestFraction=0.4m; decimal minSpreadToEnter = 0.25m; // for entry decimal FeeMultiplier = 4; // for exit int PendingOrderWaitSec = 1*60; OrderTicket order1 = null; OrderTicket order2 = null; int MyShares1, MyShares2; DateTime tradingTime; TradingState tradingState = TradingState.OutOfMarket; decimal entrySpread = 0; Resolution resolution = Resolution.Second; string baseSymbol = "SPY"; TradeBar baseBar = new TradeBar(); List<string> namePair = new List<string>() { "TYD", "DRN" }; List<decimal> spreadPair = new List<decimal> { 0.001m, 0.02m }; List<TradeBar> barPairNow = new List<TradeBar>() { new TradeBar(), new TradeBar() }; List<TradeBar> barPairPrev = new List<TradeBar>() { new TradeBar(), new TradeBar() }; public override void Initialize() { SetStartDate(2018, 9, 17); // 2012, 3, 10 SetEndDate(2018, 9, 17); SetCash(1000*20); AddSecurity(SecurityType.Equity, namePair[0], resolution); Securities[namePair[0]].TransactionModel = new MyTransactionModel( spreadPair[0], this); AddSecurity(SecurityType.Equity, namePair[1], resolution); Securities[namePair[1]].TransactionModel = new MyTransactionModel(spreadPair[1], this); AddSecurity(SecurityType.Equity, baseSymbol, resolution); Securities[baseSymbol].TransactionModel = new MyTransactionModel(0.0m, this); // spy 0.01% barPairPrev[0].Close = 88.90m; barPairPrev[1].Close = 25.94m; barPairNow[0].Close = 88.90m; barPairNow[1].Close = 25.94m; } // Initalize public void OnData(TradeBars data) { TradeBar temp1 = null; TradeBar temp2 = null; data.TryGetValue(namePair[0], out temp1); data.TryGetValue(namePair[1], out temp2); if ( temp1 != null && temp2 != null) { if ( Time.Hour == 15 && Time.Minute == 59 && Time.Second == 59 ) { // get the closing amount barPairPrev[0] = temp1; barPairPrev[1] = temp2; } else { barPairNow[0] = temp1; barPairNow[1] = temp2; } // else if ( barPairNow[0].Close>0 && barPairNow[1].Close>0 && barPairPrev[0].Close>0 && barPairPrev[1].Close>0 ) { if ( printNextBar==true ) { Console.WriteLine( "{0}, barPairNow[0]={1:F3}, high={2:F3}, low={3:F3}, vol={4:F3}", Time, barPairNow[0].Close, barPairNow[0].High, barPairNow[0].Low, barPairNow[0].Volume ); Console.WriteLine( "{0}, barPairNow[1]={1:F3}, high={2:F3}, low={3:F3}, vol={4:F3}", Time, barPairNow[1].Close, barPairNow[1].High, barPairNow[1].Low, barPairNow[1].Volume ); printNextBar = false; } ProcessBar(); } }// if else { if ( temp1 == null) Console.WriteLine("{0} temp1 is null - {1}", Time, namePair[0]); if ( temp2 == null) Console.WriteLine("{0} temp2 is null - {1}", Time, namePair[1]); } } // OnData private int CalculateQuantity( decimal price, decimal portfolioFraction) { decimal Money = portfolioFraction * Portfolio.TotalPortfolioValue; decimal entryPrice = price; int rawShares = (int) (Money/ entryPrice ); decimal IBFee = 0.005m*rawShares; BiDirectionalIBFees += 2*IBFee; int rtn = (int) ((Money -IBFee - 100)/entryPrice); return rtn; } private void HandleState_InMarket() { if ( IsExit(barPairNow, barPairPrev, minGain, out myCurrentSpread, entrySpread) ) { decimal finalExitPrice1 = barPairNow[0].Close +0.01m;// - spreadPair[0]/2; if ( MyShares1 >= 1) { order1 = LimitOrder(namePair[0], -MyShares1, Math.Round(finalExitPrice1,2) ); Console.WriteLine( "{0} EXIT order1 sent, .status={1}, limit= {2:F3}, curPrice={3:F3}, high={4:F3},low={5:F3}, vol={6:F3} ", Time, order1.Status,finalExitPrice1, barPairNow[0].Close, barPairNow[0].High, barPairNow[0].Low, barPairNow[0].Volume); } decimal finalExitPrice2 = barPairNow[1].Close - spreadPair[1]/2; if ( MyShares1 >= 1) { order2 = LimitOrder(namePair[1], -MyShares2, Math.Round(finalExitPrice2,2) ); Console.WriteLine( "{0} EXIT order2 sent, .status={1}, limit= {2:F3}, curPrice={3:F3}, high={4:F3},low={5:F3}, vol={6:F3}", Time, order1.Status,finalExitPrice2, barPairNow[1].Close, barPairNow[1].High, barPairNow[1].Low, barPairNow[1].Volume); } MyShares1 = MyShares2 = 0; Console.WriteLine( "{0} Exit orders sent ", Time); printNextBar = true; Console.WriteLine("{0}, Will print next bar", Time); tradingState = TradingState.PendingOrderExit; entryPortfolioValue = 0; } // if } private void HandleSTate_OutOfMrket() { decimal curSpread = 0; if ( IsEntry( barPairNow, barPairPrev, minSpreadToEnter, out curSpread ) ) { try { entrySpread = curSpread; tradingState = TradingState.PendingOrderEnter; tradingTime = Time; decimal entryPrice1 = barPairNow[0].Close + 0.02m; MyShares1 = CalculateQuantity( entryPrice1 , 0.3m); decimal finalEntryPrice1 = Math.Round(entryPrice1,2); if ( MyShares1 > 0) { order1 = LimitOrder(namePair[0], MyShares1, finalEntryPrice1 ); Console.WriteLine( "{0} BUY order1 sent, .status={1}, limit= {2:F3}, curPrice={3:F3}, high={4:F3},low={5:F3}, vol={6:F3}", Time, order1.Status,finalEntryPrice1,barPairNow[0].Close, barPairNow[0].High, barPairNow[0].Low, barPairNow[0].Volume); } else { //Console.WriteLine("{0}, Bad shares = {1}, price = {2}", Time, MyShares1, barPairNow[0].Close); order1 = null; } decimal entryPrice2 = barPairNow[1].Close + 0.02m; MyShares2 = CalculateQuantity( entryPrice2, 0.3m ); decimal finalEntryPrice2 = Math.Round(entryPrice2,2); if ( MyShares2 > 0) { order2 = LimitOrder(namePair[1], MyShares2, finalEntryPrice2 ); Console.WriteLine( "{0} BUY order2 sent, .status={1}, limit= {2:F3}, curPrice={3:F3}, high={4:F3},low={5:F3}, vol={6:F3}", Time, order2.Status, finalEntryPrice2, barPairNow[1].Close, barPairNow[1].High, barPairNow[1].Low, barPairNow[1].Volume); } else { //Console.WriteLine("{0}, Bad shares = {1}, price = {2}", Time, MyShares2, barPairNow[1].Close); order2 = null; } printNextBar = true; Console.WriteLine("{0}, Will print next bar", Time); entryPortfolioValue = Portfolio.TotalPortfolioValue; } catch( Exception e) { Console.WriteLine( "{0} Exception(HandleSTate_OutOfMrket)=> {1} ", Time, e.Message); } } // IsEntry is true } private void HandleState_PendingOrderEnter() { if ( order1!=null && order1.Status == OrderStatus.Filled && order2!=null && order2.Status == OrderStatus.Filled ) { tradingState = TradingState.InMarket; tradingTime = Time; Console.WriteLine( "{0} Entry Orders Executed , order1.FilledPrice={1}, order2.FilledProce={2}" , Time, order1.AverageFillPrice, order2.AverageFillPrice ); } else if ( (Time-tradingTime).TotalSeconds >=PendingOrderWaitSec || Time.Hour==15 && Time.Minute>=59 ) { if (order1!=null && order1.Status != OrderStatus.Filled && order1.Status != OrderStatus.PartiallyFilled) { order1.Cancel("entry order1 canceled " + Time.ToString()); //Console.WriteLine( "{0} entry order1 canceled", Time); } if (order2!=null && order2.Status != OrderStatus.Filled && order2.Status != OrderStatus.PartiallyFilled) { order2.Cancel("entry order2 canceled " + Time.ToString() ); //Console.WriteLine( "{0} entry order2 canceled", Time); } Console.WriteLine( "{0} \t PendingOrderEnterCancelationSent", Time); tradingState = TradingState.PendingOrderEnterCancelationSent; tradingTime = Time; } // if } private void HandleState_PendingOrderEnterCancelationSent() { MyShares1 = MyShares2 = 0; Liquidate(); Console.WriteLine( "{0} \t HandleState_PendingOrderEnterCancelationSent - Liquidated ALL entry orders if any", Time); tradingState = TradingState.OutOfMarket; tradingTime = Time; } private void HandleState_PendingOrderExit() { if ( order1!=null && order1.Status == OrderStatus.Filled && order2!=null && order2.Status == OrderStatus.Filled ) { tradingState = TradingState.OutOfMarket; tradingTime = Time; Console.WriteLine( "{0} EXIT Orders Executed , order1.FilledPrice={1}, order2.FilledProce={2}" , Time, order1.AverageFillPrice, order2.AverageFillPrice ); } else if ( (Time-tradingTime).TotalSeconds >=PendingOrderWaitSec || Time.Hour==15 && Time.Minute>=59) { if (order1!=null && order1.Status != OrderStatus.Filled && order1.Status != OrderStatus.PartiallyFilled) { order1.Cancel("exit order1 canceled " + Time.ToString()); Console.WriteLine( "{0} exit order1 canceled", Time); } if (order2!=null && order2.Status != OrderStatus.Filled && order2.Status != OrderStatus.PartiallyFilled) { order2.Cancel("exit order2 canceled " + Time.ToString()); Console.WriteLine( "{0} exit order2 canceled", Time); } tradingState = TradingState.PendingOrderExitCancelationSent; tradingTime = Time; } // if } private void HandleState_PendingOrderExitCancelationSent() { MyShares1 = MyShares2 = 0; Liquidate(); Console.WriteLine( "{0} \t HandleState_PendingOrderExitCancelationSent - Liquidated ALL exit orders if any", Time); tradingState = TradingState.OutOfMarket; tradingTime = Time; } private void ProcessBar() { try { switch( tradingState ) { case TradingState.OutOfMarket: HandleSTate_OutOfMrket(); break; case TradingState.PendingOrderEnter: HandleState_PendingOrderEnter(); break; case TradingState.PendingOrderEnterCancelationSent: HandleState_PendingOrderEnterCancelationSent(); break; case TradingState.PendingOrderExit: HandleState_PendingOrderExit(); break; case TradingState.PendingOrderExitCancelationSent: HandleState_PendingOrderExitCancelationSent(); break; case TradingState.InMarket: HandleState_InMarket(); break; } // switch } catch (Exception ex) { Error("Liquidate-all, Algorithm->ProcessBar: " + ex.Message + "\r\n\r\n" + ex.StackTrace); // reset everything Liquidate(); MyShares1 = MyShares2 = 0; order1 = order2 = null; tradingTime = Time; tradingState = TradingState.OutOfMarket; } } // ProcessBar bool IsEntry( List<TradeBar> pairNow, List<TradeBar> pairPrev, decimal minSpread, out decimal spread) { spread = 0; bool rtn = false; if ( Time.Minute == 15 && tradingState == TradingState.OutOfMarket) { rtn = true; } return rtn; } // IsEntry bool IsExit( List<TradeBar> pairNow, List<TradeBar> pairPrev, decimal minGain, out decimal myCurrentSpread, decimal myEntrySpread) { bool rtn = false; myCurrentSpread = 0; if ( Time.Hour==15 && Time.Minute==58 && tradingState == TradingState.InMarket ) { rtn = true; } if ( rtn==false && Time.Minute == 33 && tradingState == TradingState.InMarket ) { rtn = true; } // if return rtn; } // IsEntry } // class } // namespace
namespace QuantConnect.Algorithm.Examples { public class TrailingStop { public decimal TrailingStopValue {get;set;} decimal TrailingStopPercent{get;set;} bool IsLong {get;set;} public TrailingStop ( decimal stopValue, decimal stopPercent, bool isLongEntry ) { TrailingStopValue = stopValue; TrailingStopPercent = stopPercent; IsLong = isLongEntry; } public bool IsTrailingExit( TradeBar b, out decimal exitPrice) { bool rtn = false; exitPrice = 0; if ( IsLong == true) { if ( b.Close / TrailingStopValue < 1-TrailingStopPercent/100) { exitPrice = b.Close; rtn = true; } } else { // short if ( b.Close / TrailingStopValue > 1+TrailingStopPercent/100 ) { exitPrice = b.Close; rtn = true; } } // update Trailing stop if needed if ( rtn != true) { if ( IsLong == true && b.Close > TrailingStopValue) TrailingStopValue = b.Close; if ( IsLong == false && b.Close < TrailingStopValue) TrailingStopValue = b.Close; } return rtn; } // IsTrailingExit } // TrailingStop }
namespace QuantConnect { /* , UXI, (SIJ): 2009-2-1 - only UXI actually Total Trades1650 Average Win1.85% Average Loss-0.53% Compounding Annual Return 113.286% Drawdown 7.700% Expectancy1.626 Net Profit103129.908% Sharpe Ratio 4.031 Loss Rate41% Win Rate59% Profit-Loss Ratio 3.49 Alpha0.525 Beta6.788 Annual Standard Deviation0.158 Annual Variance0.025 Information Ratio3.927 Tracking Error0.158 Treynor Ratio0.094 VMIN 2016-5-2, 2.59/2.60 but low volume and Size=1 TVIX - 11/29/2010 (market down) bid/ask 9.92/9.93, URTY, SRTY: 2010-2-20 Total Trades2628 Average Win1.84% Average Loss-1.16% Compounding Annual Return 72.684% Drawdown 21.800% Expectancy0.312 Net Profit8294.308% Sharpe Ratio 1.925 Loss Rate49% Win Rate51% Profit-Loss Ratio1.58 Alpha0.456 Beta1.545 Annual Standard Deviation0.25 Annual Variance0.062 Information Ratio1.859 TNA, TZA (Small Cap) Total Trades2974 Average Win2.03% Average Loss-1.28% Compounding Annual Return 67.088% Drawdown 26.500% Expectancy0.271 Net Profit10913.068% Sharpe Ratio 1.674 Loss Rate51% Win Rate49% Profit-Loss Ratio1.59 Alpha0.41 Beta3.069 Annual Standard Deviation0.275 Annual Variance0.076 Information Ratio1.614 Tracking Error0.275 Treynor Ratio0.15 UPRO, SPXU (S&P 500 etfs) Total Trades2822 Average Win1.33% Average Loss-0.80% Compounding Annual Return 37.313% Drawdown 12.900% Expectancy0.274 Net Profit1725.062% Sharpe Ratio 1.614 Loss Rate52% Win Rate48% Profit-Loss Ratio1.67 Alpha0.423 Beta-8.926 Annual Standard Deviation0.171 Annual Variance0.029 Information Ratio1.518 Tracking Error0.171 Treynor Ratio-0.031 UBIO, ZBIO (Biotech): 2015-5-10 Total Trades928 Average Win2.36% Average Loss-1.77% Compounding Annual Return 71.381% Drawdown 29.500% Expectancy0.213 Net Profit374.516% Sharpe Ratio 1.515 Loss Rate48% Win Rate52% Profit-Loss Ratio1.34 Alpha0.486 Beta0.721 Annual Standard Deviation0.328 Annual Variance0.108 Information Ratio1.465 TQQQ, SQQQ Total Trades2632 Average Win1.56% Average Loss-0.96% Compounding Annual Return 36.082% Drawdown 14.400% Expectancy0.241 Net Profit1580.533% Sharpe Ratio 1.435 Loss Rate53% Win Rate 47% Profit-Loss Ratio1.63 Alpha0.279 Beta-0.465 Annual Standard Deviation 0.189 UDOW, SDOW Total Trades2632 Average Win1.20% Average Loss-0.74% Compounding Annual Return 30.606% Drawdown 15.900% Expectancy0.267 Net Profit1053.665% Sharpe Ratio 1.574 Loss Rate52% Win Rate 48% Profit-Loss Ratio1.64 Alpha0.472 Beta-14.679 Annual Standard Deviation 0.147 Annual Variance 0.021 Information Ratio1.461 Tracking Error0.147 Treynor Ratio-0.016 -------------2x leveraged ------------- UWM, TWM (Russel 2000) Total Trades2978 Average Win1.39% Average Loss-0.85% Compounding Annual Return 45.887% Drawdown 19.100% Expectancy0.289 Net Profit3081.668% Sharpe Ratio 1.769 Loss Rate51% Win Rate49% Profit-Loss Ratio1.63 Alpha0.281 Beta2.875 Annual Standard Deviation0.186 Annual Variance0.034 Information Ratio1.68 SSO, SDS Total Trades2978 Average Win0.93% Average Loss-0.58% Compounding Annual Return 25.242% Drawdown 9.800% Expectancy0.250 Net Profit686.193% Sharpe Ratio 1.507 Loss Rate52% Win Rate48% Profit-Loss Ratio1.60 Alpha0.241 Beta-2.889 Annual Standard Deviation0.129 Annual Variance0.017 Information Ratio1.379 QLD, QID - Total Trades2978 Average Win1.15% Average Loss-0.71% Compounding Annual Return 23.397% Drawdown 15.500% Expectancy0.194 Net Profit586.258% Sharpe Ratio 1.233 Loss Rate54% Win Rate46% Profit-Loss Ratio1.61 Alpha0.159 Beta1.542 Annual Standard Deviation0.149 Annual Variance0.022 Information Ratio1.123 =================================== LONG VXX SYmbols (shorting uptranding market) ===================================== TVIX: 2013-11-11 bid/ask 9.92/9.93, VMIN also is 2.59/2.60 but low volume and Size=1 Total Trades702 Average Win2.57% Average Loss-1.24% Compounding Annual Return 41.088% Drawdown 15.200% Expectancy0.374 Net Profit354.288% Sharpe Ratio 1.446 Loss Rate55% Win Rate45% Profit-Loss Ratio 2.07 Alpha0.44 LABD: 2015-6-1 - Biotech (but long (LABU) is BAD ?!!) Total Trades456 Average Win3.08% Average Loss-1.95% Compounding Annual Return 102.914% Drawdown 13.700% Expectancy0.485 Net Profit640.855% Sharpe Ratio 2.101 Loss Rate43% Win Rate57% Profit-Loss Ratio1.59 Alpha0.211 Beta25.269 Annual Standard Deviation0.298 Annual Variance0.089 Information Ratio2.046 ZBIO: 2015-5-10, vol=47,000 Total Trades446 Average Win2.36% Average Loss-1.38% Compounding Annual Return 56.279% Drawdown 14.500% Expectancy0.445 Net Profit263.458% Sharpe Ratio 1.809 Loss Rate47% Win Rate53% Profit-Loss Ratio1.71 Alpha0.261 Beta7.889 Annual Standard Deviation0.216 Annual Variance0.047 Information Ratio1.733 SRTY - 02/11/2010 Total Trades1242 Average Win1.43% Average Loss-0.84% Compounding Annual Return 23.058% Drawdown 12.400% Expectancy0.338 Net Profit440.411% Sharpe Ratio 1.372 Loss Rate50% Win Rate50% Profit-Loss Ratio 1.70 Alpha-0.008 Beta11.363 Annual Standard Deviation0.131 MIDZ: 2009-2-1 otal Trades1396 Average Win1.40% Average Loss-0.66% Compounding Annual Return 22.930% Drawdown 13.700% Expectancy0.425 Net Profit562.841% Sharpe Ratio 1.445 Loss Rate54% Win Rate46% Profit-Loss Ratio2.11 Alpha0.186 Beta-0.499 Annual Standard Deviation0.123 Annual Variance0.015 Information Ratio1.311 TZA: 2008-11-5 Total Trades1398 Average Win1.50% Average Loss-0.87% Compounding Annual Return 20.581% Drawdown 13.700% Expectancy0.307 Net Profit479.272% Sharpe Ratio 1.2 Loss Rate52% Win Rate48% Profit-Loss Ratio1.74 Alpha0.131 Beta1.94 Annual Standard Deviation0.136 Annual Variance0.019 Information Ratio1.079 TWM - 2009-2-1 Total Trades1396 Average Win1.04% Average Loss-0.60% Compounding Annual Return 13.725% Drawdown 10.500% Expectancy0.294 Net Profit224.883% Sharpe Ratio 1.159 Loss Rate53% Win Rate47% Profit-Loss Ratio1.75 Alpha0.088 Beta1.333 Annual Standard Deviation0.095 Annual Variance0.009 Information Ratio0.986 SOXS: Semiconductors Total Trades1240 Average Win1.73% Average Loss-1.28% Compounding Annual Return 18.259% Drawdown 30.600% Expectancy0.189 Net Profit288.007% Sharpe Ratio 0.899 Loss Rate50% Win Rate50% Profit-Loss Ratio1.35 Alpha0.155 Beta-0.179 Annual Standard Deviation0.169 Annual Variance0.029 Information Ratio0.802 SPXU - 6/23/2009 Total Trades1334 Average Win0.89% Average Loss-0.56% Compounding Annual Return 6.278% Drawdown 11.100% Expectancy0.151 Net Profit70.572% Sharpe Ratio 0.666 Loss Rate55% Win Rate45% Profit-Loss Ratio1.58 Alpha0.122 SQQQ: 2010-4-1 Total Trades1230 Average Win1.24% Average Loss-0.72% Compounding Annual Return 13.374% Drawdown 12.900% Expectancy0.241 Net Profit172.863% Sharpe Ratio 1.002 Loss Rate55% Win Rate45% Profit-Loss Ratio1.74 Alpha0.129 SDOW: 2010-2-9 Total Trades1242 Average Win0.81% Average Loss-0.54% Compounding Annual Return 4.334% Drawdown 10.200% Expectancy0.110 Net Profit41.218% Sharpe Ratio 0.53 Loss Rate56% Win Rate44% Profit-Loss Ratio1.50 Alpha0.097 FAZ: 2008-11-10 Total Trades1374 Average Win1.20% Average Loss-0.80% Compounding Annual Return 10.720% Drawdown 13.100% Expectancy0.189 Net Profit160.090% Sharpe Ratio 0.756 Loss Rate52% Win Rate48% Profit-Loss Ratio1.50 Alpha0.203 Beta-6.829 Annual Standard Deviation0.12 Annual Variance0.014 Information Ratio0.619 */ }
namespace QuantConnect.Algorithm.Examples { public class MyTransactionModel : EquityTransactionModel { private decimal SlippagePercent {get;set;} /// <summary> /// Initialize the default transaction model class /// </summary> public MyTransactionModel( decimal slippage, QCAlgorithm a) { SlippagePercent = slippage; } public override decimal GetSlippageApproximation(Security asset, Order order) { var lastData = asset.GetLastData(); if (lastData == null) return 0; decimal slippage = lastData.Value * SlippagePercent/100m; return slippage; } } // class }
using System.Collections.Generic; using NodaTime; using QuantConnect.Data; using QuantConnect.Data.Custom; namespace QuantConnect.Algorithm.Examples { public class DrawDPoint { public decimal DD; public decimal upVal; public decimal downVal; public DateTime upValTime; public DateTime downValTime; public DateTime recoverTime; public DrawDPoint( DrawDPoint d ) { DD = d.DD; upVal= d.upVal; downVal= d.downVal; upValTime= d.upValTime; downValTime = d.downValTime; } public DrawDPoint( ) {} } // class public class DrawDown { public DrawDPoint GetDD( List<TradeBar> bars ) { DrawDPoint worst=new DrawDPoint(); DrawDPoint cur = new DrawDPoint(); worst.DD=0; worst.upVal = worst.downVal = bars[0].Close; worst.upValTime = worst.downValTime = bars[0].Time; cur.DD = 0; cur.upVal = cur.downVal = bars[0].Close; cur.upValTime = cur.downValTime = bars[0].Time; for(int i=1; i<bars.Count; i++) { // check if it needs to be set as recovery for worst if ( worst.recoverTime == DateTime.MinValue && bars[i].Close>worst.upVal ) { // this is first exceed, we can set recovery worst.recoverTime = bars[i].Time; } // check for new peak if ( bars[i].Close>cur.upVal ) { // reset current cur.upVal = bars[i].Close; cur.upValTime = bars[i].Time; cur.downVal = bars[i].Close; cur.downValTime = bars[i].Time; cur.DD = cur.upVal-cur.downVal; } else { // check for new min if (bars[i].Close < cur.downVal ) { // new min found cur.downVal = bars[i].Close; cur.downValTime = bars[i].Time; cur.DD = cur.upVal-cur.downVal; // since this is a new min, check for drawdown if ( cur.DD > worst.DD ) { // found new worst DD worst = new DrawDPoint( cur); } else { // not a new drawdown, do nothing } } // if else { // no peak, no min - do nothing } } // else } // for i return worst; } // GetDD } // class DrawDown } // namespace