/// <summary> /// Checks if the limits order are filled, and updates the ITrenStrategy object and the /// LastOrderSent dictionary. /// If the limit order aren't filled, then cancels the order and send a market order. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="lastOrder">The last order.</param> private void CheckOrderStatus(string symbol, OrderSignal lastOrder) { int shares; // If the ticket isn't filled... if (_ticketsQueue.Last().Status != OrderStatus.Filled) { shares = _ticketsQueue.Last().Quantity; // cancel the limit order and send a new market order. _ticketsQueue.Last().Cancel(); _ticketsQueue.Add(MarketOrder(symbol, shares)); } // Once the ticket is filled, update the ITrenStrategy object for the symbol. if (lastOrder == OrderSignal.goLong) { iTrendSignal.Position = StockState.longPosition; } else if (lastOrder == OrderSignal.goShort) { iTrendSignal.Position = StockState.shortPosition; } iTrendSignal.EntryPrice = _ticketsQueue.Last().AverageFillPrice; // Update the LastOrderSent dictionary, to avoid check filled orders many times. LastOrderSent[symbol] = OrderSignal.doNothing; // TODO: If the ticket is partially filled. }
/// <summary> /// Executes the order. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualSignal">The actual signal.</param> private void ExecuteOrder(string symbol, OrderSignal actualSignal, MomersionState actualSenderStrategy) { int?shares; int newOrderID; switch (actualSignal) { case OrderSignal.goShort: case OrderSignal.goLong: // Estimate the operation shares and submit an order only if the estimation returns not null shares = EstimatePosition(symbol, actualSignal); if (shares.HasValue) { newOrderID = Transactions.LastOrderId + 1; SenderStrategy.Add(newOrderID, actualSenderStrategy); MarketOrder(symbol, shares.Value); } break; case OrderSignal.closeShort: case OrderSignal.closeLong: shares = Portfolio[symbol].Quantity; newOrderID = Transactions.LastOrderId + 1; SenderStrategy.Add(newOrderID, actualSenderStrategy); MarketOrder(symbol, -shares.Value); break; default: break; } }
/// <summary> /// Sells out all positions at 15:50, and calculates the profits for the day /// emails the transactions for the day to me /// </summary> /// <param name="data">TradeBars - the data</param> /// <param name="signalInfosMinute"></param> /// <returns>false if end of day, true during the day </returns> private void SellOutAtEndOfDay(KeyValuePair <Symbol, TradeBar> data, ref OrderSignal signal) { if (shouldSellOutAtEod) { #region logging if (Time.Hour == 16) { sharesOwned = Portfolio[symbol].Quantity; #region logging SendTransactionsToFile(); #endregion NotifyUser(); } #endregion if (Time.Hour == 15 && Time.Minute > 45) { signal = OrderSignal.doNothing; if (Portfolio[symbol].IsLong) { signal = OrderSignal.goShort; } if (Portfolio[symbol].IsShort) { signal = OrderSignal.goLong; } } } }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual arder to be execute.</param> /// <param name="data">The actual TradeBar data.</param> private void ExecuteStrategy(Symbol symbol, OrderSignal actualOrder, TradeBars data) { decimal limitPrice = 0m; int shares = PositionShares(symbol, actualOrder); ILimitPriceCalculator priceCalculator = new InstantTrendLimitPriceCalculator(); switch (actualOrder) { case OrderSignal.goLongLimit: // Define the limit price. limitPrice = priceCalculator.Calculate(data[symbol], actualOrder, RngFac); _ticketsQueue.Enqueue(LimitOrder(symbol, shares, limitPrice)); break; case OrderSignal.goShortLimit: limitPrice = priceCalculator.Calculate(data[symbol], actualOrder, RngFac); _ticketsQueue.Enqueue(LimitOrder(symbol, shares, limitPrice)); break; case OrderSignal.goLong: case OrderSignal.goShort: case OrderSignal.closeLong: case OrderSignal.closeShort: case OrderSignal.revertToLong: case OrderSignal.revertToShort: _ticketsQueue.Enqueue(MarketOrder(symbol, shares)); // Send the order. break; default: break; } }
public void OnData(TradeBars data) { bool isMarketAboutToClose = !theMarket.DateTimeIsOpen(Time.AddMinutes(10)); OrderSignal actualOrder = OrderSignal.doNothing; int i = 0; foreach (string symbol in Symbols) { // Operate only if the market is open if (theMarket.DateTimeIsOpen(Time)) { // First check if there are some limit orders not filled yet. if (Transactions.LastOrderId > 0) { CheckLimitOrderStatus(symbol); } // Check if the market is about to close and noOvernight is true. if (noOvernight && isMarketAboutToClose) { actualOrder = ClosePositions(symbol); } else { // Now check if there is some signal and execute the strategy. actualOrder = Strategy[symbol].ActualSignal; } ExecuteStrategy(symbol, actualOrder); } #region Logging stuff - Filling the data StockLogging //"Counter, Time, Close, ITrend, Trigger," + //"Momentum, EntryPrice, Signal," + //"TriggerCrossOverITrend, TriggerCrossUnderITrend, ExitFromLong, ExitFromShort," + //"StateFromStrategy, StateFromPorfolio, Portfolio Value" string newLine = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14}", barCounter, Time, (data[symbol].Close + data[symbol].Open) / 2, Strategy[symbol].ITrend.Current.Value, Strategy[symbol].ITrend.Current.Value + Strategy[symbol].ITrendMomentum.Current.Value, Strategy[symbol].ITrendMomentum.Current.Value, (Strategy[symbol].EntryPrice == null) ? 0 : Strategy[symbol].EntryPrice, actualOrder, Strategy[symbol].TriggerCrossOverITrend.ToString(), Strategy[symbol].TriggerCrossUnderITrend.ToString(), Strategy[symbol].ExitFromLong.ToString(), Strategy[symbol].ExitFromShort.ToString(), Strategy[symbol].Position.ToString(), Portfolio[symbol].Quantity.ToString(), Portfolio.TotalPortfolioValue ); stockLogging[i].AppendLine(newLine); i++; #endregion Logging stuff - Filling the data StockLogging } barCounter++; // just for debug }
/// <summary> /// Estimate number of shares, given a kind of operation. /// </summary> /// <param name="symbol">The symbol to operate.</param> /// <param name="order">The kind of order.</param> /// <returns>The signed number of shares given the operation.</returns> public int PositionShares(string symbol, OrderSignal order) { int quantity; int operationQuantity; switch (order) { case OrderSignal.goLong: case OrderSignal.goLongLimit: operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]); quantity = Math.Min(maxOperationQuantity, operationQuantity); break; case OrderSignal.goShort: case OrderSignal.goShortLimit: operationQuantity = CalculateOrderQuantity(symbol, -ShareSize[symbol]); quantity = Math.Max(-maxOperationQuantity, operationQuantity); break; case OrderSignal.closeLong: case OrderSignal.closeShort: quantity = -Portfolio[symbol].Quantity; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: quantity = -2 * Portfolio[symbol].Quantity; break; default: quantity = 0; break; } return(quantity); }
/// <summary> /// Sells out all positions at 15:50, and calculates the profits for the day /// emails the transactions for the day to me /// </summary> /// <param name="data">TradeBars - the data</param> /// <param name="signalInfosMinute"></param> /// <param name="signal">the current OrderSignal</param> /// <returns>false if end of day, true during the day </returns> private void SellOutAtEndOfDay(KeyValuePair <Symbol, TradeBar> data, ref OrderSignal signal) { if (shouldSellOutAtEod) { #region logging if (Time.Hour == 16) { NotifyUser(); signal = OrderSignal.doNothing; } #endregion if (Time.Hour == 15 && Time.Minute > 45) { signal = OrderSignal.doNothing; if (Portfolio[data.Key].IsLong) { signal = OrderSignal.goShort; } if (Portfolio[data.Key].IsShort) { signal = OrderSignal.goLong; } } } }
public void OnData(TradeBars data) { bool isMarketAboutToClose = !theMarket.DateTimeIsOpen(Time.AddMinutes(10)); OrderSignal actualOrder = OrderSignal.doNothing; int i = 0; foreach (string symbol in Symbols) { // Operate only if the market is open if (theMarket.DateTimeIsOpen(Time)) { // First check if there are some limit orders not filled yet. if (Transactions.LastOrderId > 0) { CheckLimitOrderStatus(symbol); } // Check if the market is about to close and noOvernight is true. if (noOvernight && isMarketAboutToClose) { actualOrder = ClosePositions(symbol); } else { // Now check if there is some signal and execute the strategy. actualOrder = Strategy[symbol].ActualSignal; } ExecuteStrategy(symbol, actualOrder); } } }
public override void CheckSignal() { OrderSignal actualSignal = OrderSignal.doNothing; #region Alternative Signals // This signal are faster but inaccurate. The tests works with this signals. //bool longSignal = (InvFisherRW[1] < -_threshold) && // (InvFisherRW[0] > -_threshold) && // (Math.Abs(InvFisherRW[0] - InvFisherRW[1]) > _tolerance); //bool shortSignal = (InvFisherRW[1] > _threshold) && // (InvFisherRW[0] < _threshold) && // (Math.Abs(InvFisherRW[0] - InvFisherRW[1]) > _tolerance); #endregion bool longSignal = (InvFisherRW[1] < _threshold) && (InvFisherRW[0] > _threshold) && (Math.Abs(InvFisherRW[0] - InvFisherRW[1]) > _tolerance) && (Momersion > 50); bool shortSignal = (InvFisherRW[1] > -_threshold) && (InvFisherRW[0] < -_threshold) && (Math.Abs(InvFisherRW[0] - InvFisherRW[1]) > _tolerance) && (Momersion > 50); switch (Position) { case StockState.shortPosition: if (longSignal) { actualSignal = OrderSignal.closeShort; } break; case StockState.longPosition: if (shortSignal) { actualSignal = OrderSignal.closeLong; } break; case StockState.noInvested: if (longSignal) { actualSignal = OrderSignal.goLong; } else if (shortSignal) { actualSignal = OrderSignal.goShort; } break; default: break; } ActualSignal = actualSignal; }
public decimal Calculate(TradeBar data, OrderSignal signal, decimal rangeFactor) { decimal nLimitPrice = 0; if (signal == OrderSignal.goLongLimit) nLimitPrice = Math.Round(Math.Max(data.Low, (data.Close - (data.High - data.Low) * rangeFactor)), 2, MidpointRounding.ToEven); if (signal == OrderSignal.goShortLimit) nLimitPrice = Math.Round(Math.Min(data.High, (data.Close + (data.High - data.Low) * rangeFactor)), 2, MidpointRounding.ToEven); return nLimitPrice; }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual order to be execute.</param> /// <param name="data">The actual TradeBar data.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder) { if (barCounter >= 21) { comment = ""; } // Define the operation size. int shares = PositionShares(symbol, actualOrder); if (shares == 0) { actualOrder = OrderSignal.doNothing; } switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: case OrderSignal.goLongLimit: case OrderSignal.goShortLimit: //Log("===> Entry to Market"); decimal limitPrice; var barPrices = Securities[symbol]; // Define the limit price. if (actualOrder == OrderSignal.goLong || actualOrder == OrderSignal.goLongLimit) { limitPrice = Math.Max(barPrices.Low, (barPrices.Close - (barPrices.High - barPrices.Low) * RngFac)); } else { limitPrice = Math.Min(barPrices.High, (barPrices.Close + (barPrices.High - barPrices.Low) * RngFac)); } // Send the order. LimitOrder(symbol, shares, limitPrice); break; case OrderSignal.closeLong: case OrderSignal.closeShort: //Log("<=== Closing Position"); // Send the order. MarketOrder(symbol, shares); break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: //Log("<===> Reverting Position"); // Send the order. MarketOrder(symbol, shares); break; default: break; } }
public decimal Calculate(TradeBar data, OrderSignal signal, decimal rangeFactor) { decimal nLimitPrice = 0; if (signal == OrderSignal.goLongLimit) { nLimitPrice = Math.Round(Math.Max(data.Low, (data.Close - (data.High - data.Low) * rangeFactor)), 2, MidpointRounding.ToEven); } if (signal == OrderSignal.goShortLimit) { nLimitPrice = Math.Round(Math.Min(data.High, (data.Close + (data.High - data.Low) * rangeFactor)), 2, MidpointRounding.ToEven); } return(nLimitPrice); }
public OrderSignal CheckSignal(TradeBars data, Dictionary <string, string> paramlist, out string comment) { PropertyInfo[] properties = GetType().GetProperties(); // make sure symbol is set first for getting trendCurrent PropertyInfo s = properties.FirstOrDefault(x => x.Name == "symbol"); if (s != null) { symbol = new Symbol(paramlist["symbol"], paramlist["symbol"]); } IndicatorDataPoint trendCurrent = new IndicatorDataPoint(data[symbol].EndTime, 0);; string trend = paramlist["trend"]; trendCurrent.Value = System.Convert.ToDecimal(trend); foreach (var item in paramlist) { PropertyInfo p = properties.FirstOrDefault(x => x.Name == item.Key); if (p != null) { if (item.Key != "symbol") { { var converter = TypeDescriptor.GetConverter(p.PropertyType); try { var convertedvalue = converter.ConvertFrom(item.Value); var setmethod = p.SetMethod; if (setmethod != null) { p.SetValue(this, convertedvalue); } } catch (Exception e) { Debug.WriteLine(e.Message); } } } } } string current; OrderSignal retval = CheckSignal(data, trendCurrent, out current); comment = current; return(retval); }
/// <summary> /// Checks the for signals. /// </summary> public override void CheckSignal() { OrderSignal actualSignal = OrderSignal.doNothing; // Defining the signals. bool longSignal = EMADiffRW[1] < 0 && EMADiffRW[0] > 0 && Math.Abs(EMADiffRW[0] - EMADiffRW[1]) > _tolerance; bool shortSignal = EMADiffRW[1] > 0 && EMADiffRW[0] < 0 && Math.Abs(EMADiffRW[0] - EMADiffRW[1]) > _tolerance; // Depending on the actual strategy position, define the signal. switch (Position) { case StockState.shortPosition: if (longSignal) { actualSignal = OrderSignal.closeShort; } break; case StockState.longPosition: if (shortSignal) { actualSignal = OrderSignal.closeLong; } break; case StockState.noInvested: if (longSignal) { actualSignal = OrderSignal.goLong; } else if (shortSignal) { actualSignal = OrderSignal.goShort; } break; default: break; } // Update the ActualSignal field. ActualSignal = actualSignal; }
public void GoLongAndClosePosition() { int _trendPeriod = 5; int _invFisherPeriod = 6; decimal _tolerance = 0.001m; decimal _threshold = 0.9m; DateTime time = DateTime.Now; # region Arrays inputs decimal[] prices = new decimal[15] { 24.51m, 24.51m, 20.88m, 15m, 9.12m, 5.49m, 5.49m, 9.12m, 15m, 20.88m, 24.51m, 24.51m, 20.88m, 15m, 9.12m, }; OrderSignal[] expectedOrders = new OrderSignal[15] { OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goLong , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.closeLong, OrderSignal.doNothing }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; Identity VoidIndicator = new Identity("Void"); DIFStrategy strategy = new DIFStrategy(VoidIndicator, _trendPeriod, _invFisherPeriod, _threshold, _tolerance); for (int i = 0; i < prices.Length; i++) { strategy.DecycleTrend.Update(new IndicatorDataPoint(time, prices[i])); // Update the InverseFisher indicator from here, if not it took 11 bars until the first signal. strategy.InverseFisher.Update(strategy.DecycleTrend.Current); actualOrders[i] = strategy.ActualSignal; if (actualOrders[i] == OrderSignal.goLong) strategy.Position = StockState.longPosition; Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
private OrderSignal CheckLossThreshhold(ref string comment, OrderSignal retval) { //if (Barcount >= 376) // System.Diagnostics.Debug.WriteLine("Barcount: " + Barcount); if (UnrealizedProfit < lossThreshhold) { if (IsLong) { retval = OrderSignal.goShortLimit; } if (IsShort) { retval = OrderSignal.goLongLimit; } comment = string.Format("Unrealized loss exceeded {0}", lossThreshhold); bReverseTrade = true; } return(retval); }
/// <summary> /// Run the strategy associated with this algorithm /// </summary> /// <param name="data">TradeBars - the data received by the OnData event</param> private string Strategy(TradeBars data) { #region "Strategy Execution" string ret = ""; if (SellOutEndOfDay(data)) { // if there were limit order tickets to cancel, wait a bar to execute the strategy iTrendStrategy.Barcount = barcount; // for debugging iTrendStrategy.nEntryPrice = nEntryPrice; signal = iTrendStrategy.ExecuteStrategy(data, tradesize, trend.Current, out comment); #region lists #endregion } #endregion return(ret); }
public void GoLongRevertAndClosePosition() { int _period = 7; decimal _tolerance = 0.00001m; decimal _revertPct = 1.015m; DateTime time = DateTime.Now; # region Arrays inputs decimal[] prices = new decimal[15] { 100m, 99m, 98m, 97m, 96m, 95m, 94m, 93m, 92m, 105m, 100m, 95m, 90m, 100m, 100m }; OrderSignal[] expectedOrders = new OrderSignal[15] { OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goLong, OrderSignal.revertToShort, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.closeShort }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; ITrendStrategy strategy = new ITrendStrategy(_period, _tolerance, _revertPct, RevertPositionCheck.vsClosePrice); for (int i = 0; i < prices.Length; i++) { strategy.ITrend.Update(new IndicatorDataPoint(time, prices[i])); actualOrders[i] = strategy.CheckSignal(prices[i]); if (actualOrders[i] == OrderSignal.goLong) { strategy.Position = StockState.longPosition; strategy.EntryPrice = prices[i]; } if (actualOrders[i] == OrderSignal.revertToShort) strategy.Position = StockState.shortPosition; Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
/// <summary> /// Estimate number of shares, given a kind of operation. /// </summary> /// <param name="symbol">The symbol to operate.</param> /// <param name="order">The kind of order.</param> /// <returns>The signed number of shares given the operation.</returns> public int PositionShares(Symbol symbol, OrderSignal order) { int quantity; int operationQuantity; decimal targetSize; targetSize = GetBetSize(symbol); switch (order) { case OrderSignal.goLongLimit: case OrderSignal.goLong: //operationQuantity = CalculateOrderQuantity(symbol, targetSize); // let the algo decide on order quantity operationQuantity = (int)targetSize; quantity = Math.Min(maxOperationQuantity, operationQuantity); break; case OrderSignal.goShortLimit: case OrderSignal.goShort: //operationQuantity = CalculateOrderQuantity(symbol, targetSize); // let the algo decide on order quantity operationQuantity = (int)targetSize; quantity = -Math.Min(maxOperationQuantity, operationQuantity); break; case OrderSignal.closeLong: case OrderSignal.closeShort: quantity = -Portfolio[symbol].Quantity; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: quantity = -2 * Portfolio[symbol].Quantity; break; default: quantity = 0; break; } return(quantity); }
public void OnData(TradeBars data) { OrderSignal actualOrder = OrderSignal.doNothing; int i = 0; // just for logging foreach (string symbol in Symbols) { if (isNormalOperativeTime) { ManageStopLoss(symbol); actualOrder = Strategy[symbol].ActualSignal; } else if (noOvernight && isMarketAboutToClose) { actualOrder = CloseAllPositions(symbol); } ExecuteStrategy(symbol, actualOrder); #region Logging stuff - Filling the data StockLogging //Time,Close,Decycle,InvFisher,LightSmoothPrice,Momersion,PSAR,Position string newLine = string.Format("{0},{1},{2},{3},{4},{5},{6},{7}", Time.ToString("u"), data[symbol].Close, Strategy[symbol].DecycleTrend.Current.Value, Strategy[symbol].InverseFisher.Current.Value, Strategy[symbol].LightSmoothPrice.Current.Value, Strategy[symbol].Momersion.Current.Value, PSARDict[symbol].Current.Value, Portfolio[symbol].Invested ? Portfolio[symbol].IsLong ? 1 : -1 : 0 ); stockLogging[i].AppendLine(newLine); i++; #endregion Logging stuff - Filling the data StockLogging } barCounter++; // just for logging }
/// <summary> /// Checks if the open market conditions are good enough to take a position. /// </summary> /// <param name="symbol">The symbol.</param> private void CheckEarlyEntry(string symbol) { OrderSignal actualOrder = OrderSignal.doNothing; if (Strategy[symbol].Momersion > 50) { if ((PSARDict[symbol] > Securities[symbol].Price) && (Strategy[symbol].InverseFisher < -Threshold)) { Log("=== Day early short entry triggered ==="); actualOrder = OrderSignal.goShort; } if ((PSARDict[symbol] < Securities[symbol].Price) && (Strategy[symbol].InverseFisher > Threshold)) { Log("=== Day early long entry triggered ==="); actualOrder = OrderSignal.goLong; } } ExecuteStrategy(symbol, actualOrder); }
public void GoShortAndClosePosition() { int _period = 7; decimal _tolerance = 0.00001m; decimal _revertPct = 1.015m; DateTime time = DateTime.Now; # region Arrays inputs decimal[] prices = new decimal[20] { 91m, 91m, 91m, 91m, 91m, 91m, 92m, 93m, 94m, 95m, 96m, 97m, 98m, 99m, 100m, 85m, 84m, 83m, 100m, 100m, }; OrderSignal[] expectedOrders = new OrderSignal[20] { OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goShortLimit , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.closeShort }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; Identity priceIdentity = new Identity("IdentityIndicator"); ITrendStrategy strategy = new ITrendStrategy(priceIdentity, _period, _tolerance, _revertPct, RevertPositionCheck.vsClosePrice); for (int i = 0; i < prices.Length; i++) { priceIdentity.Update(new IndicatorDataPoint(time, prices[i])); actualOrders[i] = strategy.ActualSignal; if (actualOrders[i] == OrderSignal.goShortLimit) strategy.Position = StockState.shortPosition; Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
/// <summary> /// Estimates the shares quantity for the next operation. It returns the quantity SIGNED /// depending on the actualSignal i.e. positive if buy, negative if sell /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualSignal">The actual signal.</param> /// <returns></returns> private int?EstimatePosition(string symbol, OrderSignal actualSignal) { int marginAvailable; int quantity; int?operationQuantity = null; // Make the estimations only if the orders are to entry in the market. if (actualSignal == OrderSignal.goLong || actualSignal == OrderSignal.goShort) { // Check the margin and the quantity to achieve target-percent holdings then choose the minimum. marginAvailable = (int)Math.Floor(Portfolio.MarginRemaining / Securities[symbol].Price); quantity = Math.Min(CalculateOrderQuantity(symbol, shareSize), marginAvailable); // Only assign a value to the operationQuantity if is bigger than a threshold. if (quantity > 10) { // Make the quantity signed accord to the order. operationQuantity = actualSignal == OrderSignal.goLong ? quantity : -quantity; } } return(operationQuantity); }
/// <summary> /// Executes the strategy. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualOrder">The actual order.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder) { int?shares; switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. if (shares.HasValue) { Log("===> Market entry order sent " + symbol); int orderShares = shares.Value; var entryOrder = MarketOrder(symbol, orderShares); // submit stop loss order for max loss on the trade decimal stopPrice = (actualOrder == OrderSignal.goLong) ? Securities[symbol].Low * (1 - GlobalStopLossPercent) : Securities[symbol].High * (1 + GlobalStopLossPercent); StopLossTickets[symbol] = StopMarketOrder(symbol, -orderShares, stopPrice); EnablePsarTrailingStop[symbol] = false; } break; case OrderSignal.closeLong: case OrderSignal.closeShort: Log("<=== Liquidate " + symbol); Liquidate(symbol); StopLossTickets[symbol].Cancel(); StopLossTickets[symbol] = null; break; default: break; } }
public int?PositionShares(string symbol, OrderSignal order, int?maxShares = null, decimal?maxAmount = null, decimal?maxPortfolioShare = null) { int?quantity; int operationQuantity; switch (order) { case OrderSignal.goLong: operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]); quantity = operationQuantity; break; case OrderSignal.goShort: operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]); quantity = -operationQuantity; break; default: quantity = null; break; } return(quantity); }
/// <summary> /// Estimate the shares to operate in the next transaction given the stock weight and the kind of order. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualOrder">The actual order.</param> /// <returns></returns> private int? PositionShares(string symbol, OrderSignal actualOrder) { int? positionQuantity = null; int quantity = 0; decimal price = Securities[symbol].Price; // Handle negative portfolio weights. if (ShareSize[symbol] < 0) { if (actualOrder == OrderSignal.goLong) actualOrder = OrderSignal.goShort; else if (actualOrder == OrderSignal.goShort) actualOrder = OrderSignal.goLong; } switch (actualOrder) { case OrderSignal.goShort: case OrderSignal.goLong: // In the first part the estimations are in ABSOLUTE VALUE! // Estimated the desired quantity to achieve target-percent holdings. quantity = Math.Abs(CalculateOrderQuantity(symbol, ShareSize[symbol])); // Estimate the max allowed position in dollars and compare it with the desired one. decimal maxOperationDollars = Portfolio.TotalPortfolioValue * maxPorfolioRiskPerPosition; decimal operationDollars = quantity * price; // If the desired is bigger than the max allowed operation, then estimate a new bounded quantity. if (maxOperationDollars < operationDollars) quantity = (int)(maxOperationDollars / price); if (actualOrder == OrderSignal.goLong) { // Check the margin availability. quantity = (int)Math.Min(quantity, Portfolio.MarginRemaining / price); } else { // In case of short sales, the margin should be a 150% of the operation. quantity = (int)Math.Min(quantity, Portfolio.MarginRemaining / (1.5m * price)); // Now adjust the sing correctly. quantity *= -1; } break; case OrderSignal.closeShort: case OrderSignal.closeLong: quantity = -Portfolio[symbol].Quantity; break; default: break; } // Only assign a value to the positionQuantity if is bigger than a threshold. If not, then it'll return null. if (Math.Abs(quantity) > minSharesPerTransaction) { positionQuantity = quantity; } return positionQuantity; }
/// <summary> /// Executes the order. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualSignal">The actual signal.</param> private void ExecuteOrder(string symbol, OrderSignal actualSignal, MomersionState actualSenderStrategy) { int? shares; int newOrderID; switch (actualSignal) { case OrderSignal.goShort: case OrderSignal.goLong: // Estimate the operation shares and submit an order only if the estimation returns not null shares = EstimatePosition(symbol, actualSignal); if (shares.HasValue) { newOrderID = Transactions.LastOrderId + 1; SenderStrategy.Add(newOrderID, actualSenderStrategy); MarketOrder(symbol, shares.Value); } break; case OrderSignal.closeShort: case OrderSignal.closeLong: shares = Portfolio[symbol].Quantity; newOrderID = Transactions.LastOrderId + 1; SenderStrategy.Add(newOrderID, actualSenderStrategy); MarketOrder(symbol, -shares.Value); break; default: break; } }
/// <summary> /// Checks if the limits order are filled, and updates the ITrenStrategy object and the /// LastOrderSent dictionary. /// If the limit order aren't filled, then cancels the order and send a market order. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="lastOrder">The last order.</param> private void CheckOrderStatus(string symbol, OrderSignal lastOrder) { int shares; // If the ticket isn't filled... if (Tickets[symbol].Last().Status != OrderStatus.Filled) { shares = Tickets[symbol].Last().Quantity; // cancel the limit order and send a new market order. Tickets[symbol].Last().Cancel(); Tickets[symbol].Add(MarketOrder(symbol, shares)); } // Once the ticket is filled, update the ITrenStrategy object for the symbol. if (lastOrder == OrderSignal.goLong) { Strategy[symbol].Position = StockState.longPosition; } else if (lastOrder == OrderSignal.goShort) { Strategy[symbol].Position = StockState.shortPosition; } Strategy[symbol].EntryPrice = Tickets[symbol].Last().AverageFillPrice; // Update the LastOrderSent dictionary, to avoid check filled orders many times. LastOrderSent[symbol] = OrderSignal.doNothing; // TODO: If the ticket is partially filled. }
/// <summary> /// Run the strategy associated with this algorithm /// </summary> /// <param name="data">TradeBars - the data received by the OnData event</param> private string GetTradingSignals(TradeBars data) { #region "strategyList Execution" string ret = ""; foreach (var s in Symbols) { if (SellOutEndOfDay(data)) { // if there were limit order tickets to cancel, wait a bar to execute the strategy if (!CanceledUnfilledLimitOrder()) { if (nEntryPrice != 0) { comment = "entryprice"; } if (barcount == 1) { comment = "bar 1"; } iTrendStrategy.Barcount = barcount; // for debugging iTrendStrategy.nEntryPrice = nEntryPrice; iTrendStrategy.maketrade = true; //signal = iTrendStrategy.ExecuteStrategy(data, tradesize, trend.Current, out comment); //if (iTrendStrategy.trendHistory[0].Value != trendHistory[0].Value) // throw new Exception("Trend history not flowing through to strategy correctly."); #region lists StringBuilder sb = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); StringBuilder sb3 = new StringBuilder(); foreach (var it in strategyList) { it.Value.Barcount = barcount; it.Value.ShouldSellOutAtEod = shouldSellOutAtEod; it.Value.nEntryPrice = entryPriceList[it.Key]; // inject the entry price it.Value.nEntryPrice = nEntryPrice1; // inject the entry price OrderSignal current = it.Value.CheckSignal(data, tradesize, trendList[it.Key].Current, out comment); // OrderSignal current = it.Value.CheckSignal(data, tradesize, trend.Current, out comment); //entryPriceList[it.Key] = it.Value.nEntryPrice; // save the entry price var thcompareS = it.Value.trendHistory[0].Value; var thcompareL = trendHistoryList[it.Key][0].Value; //if (thcompareL != thcompareS) // throw new Exception("Trend history not flowing through strategy correctly."); //if (signal != current) // comment = "signals not the same"; #region logging sb.Append(((int)current).ToString(CultureInfo.InvariantCulture)); sb.Append(","); sb2.Append(it.Value.sTrig); sb2.Append(","); sb3.Append(it.Value.trendHistory[0].Value); sb3.Append(@","); #endregion if (current != OrderSignal.doNothing) { //ExecuteStrategy(s, entryPriceList[it.Key], current, data); ExecuteStrategy(s, nEntryPrice, current, data); } } ret = sb.ToString() + "," + sb2.ToString() + "," + sb3.ToString(); #endregion } } } #endregion return(ret); }
public void TestingTolerance() { int _period = 7; decimal _tolerance = 0.15m; decimal _revertPct = 1.015m; DateTime time = DateTime.Now; # region Arrays inputs decimal[] prices = new decimal[15] { 99m, 99.25m, 99.5m, 99.75m, 100m, 100.25m, 100.5m, 100.75m, 100m, 100m, 100.1m, 100.2m, 100.3m, 100.4m, 100.5m, }; OrderSignal[] expectedOrders = new OrderSignal[15] { OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goShort, OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; ITrendStrategy strategy = new ITrendStrategy(_period, _tolerance, _revertPct, RevertPositionCheck.vsClosePrice); for (int i = 0; i < prices.Length; i++) { strategy.ITrend.Update(new IndicatorDataPoint(time, prices[i])); actualOrders[i] = strategy.CheckSignal(prices[i]); Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
public OrderSignal CheckSignal(KeyValuePair <Symbol, TradeBar> data, IndicatorDataPoint trendCurrent, out string comment) { OrderSignal retval = OrderSignal.doNothing; comment = string.Empty; UpdateTrendArray(trendCurrent.Value); bReverseTrade = false; ReverseTrade = false; NTrigGTEP = false; NTrigLTEP = false; NTrigGTTA0 = false; NTrigLTTA0 = false; BarcountLT4 = false; OrderFilled = orderFilled; if (Barcount < 4) { BarcountLT4 = true; comment = "Barcount < 4"; retval = OrderSignal.doNothing; } else { nTrig = 2m * trendArray[0] - trendArray[2]; #region "Selection Logic Reversals" retval = CheckLossThreshhold(ref comment, retval); if (nTrig < (Math.Abs(nEntryPrice) / RevPct)) { NTrigLTEP = true; if (IsLong) { retval = OrderSignal.revertToShort; bReverseTrade = true; ReverseTrade = true; comment = string.Format("nTrig {0} < (nEntryPrice {1} * RevPct {2}) {3} IsLong {4} )", Math.Round(nTrig, 4), nEntryPrice, RevPct, NTrigLTEP, IsLong); } else { NTrigLTEP = false; } } else { if (nTrig > (Math.Abs(nEntryPrice) * RevPct)) { NTrigGTEP = true; if (IsShort) { retval = OrderSignal.revertToLong; bReverseTrade = true; ReverseTrade = true; comment = string.Format("nTrig {0} > (nEntryPrice {1} * RevPct {2}) {3} IsLong {4} )", Math.Round(nTrig, 4), nEntryPrice, RevPct, NTrigLTEP, IsLong); } else { NTrigGTEP = false; } } } #endregion #region "selection logic buy/sell" retval = CheckLossThreshhold(ref comment, retval); if (!bReverseTrade) { if (nTrig > trendArray[0]) { NTrigGTTA0 = true; if (xOver == -1) { #region "If Not Long" if (!IsLong) { if (!orderFilled) { retval = OrderSignal.goLong; comment = string.Format( "nTrig {0} > trend {1} xOver {2} !IsLong {3} orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsLong, orderFilled); } else { retval = OrderSignal.goLongLimit; comment = string.Format( "nTrig {0} > trend {1} xOver {2} !IsLong {3} orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsLong, orderFilled); } } #endregion } if (comment.Length == 0) { comment = "Trigger over trend - setting xOver to 1"; } xOver = 1; xOverisNegative = xOver < 0; xOverIsPositive = xOver > 0; } else { if (nTrig < trendArray[0]) { NTrigLTTA0 = true; if (xOver == 1) { #region "If Not Short" if (!IsShort) { if (!orderFilled) { retval = OrderSignal.goShort; comment = string.Format( "nTrig {0} < trend {1} xOver {2} !isShort {3} orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsShort, !orderFilled); } else { retval = OrderSignal.goShortLimit; comment = string.Format( "nTrig {0} < trend {1} xOver {2} !isShort {3} orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsShort, !orderFilled); } } #endregion } if (comment.Length == 0) { comment = "Trigger under trend - setting xOver to -1"; } xOver = -1; xOverisNegative = xOver < 0; xOverIsPositive = xOver > 0; } } } #endregion } StringBuilder sb = new StringBuilder(); sb.Append(comment); comment = sb.ToString(); return(retval); }
/// <summary> /// Sells out all positions at 15:50, and calculates the profits for the day /// emails the transactions for the day to me /// </summary> /// <param name="data">TradeBars - the data</param> /// <param name="signalInfosMinute"></param> /// <returns>false if end of day, true during the day </returns> private void SellOutAtEndOfDay(KeyValuePair<Symbol, TradeBar> data, ref OrderSignal signal) { if (shouldSellOutAtEod) { #region logging if (Time.Hour == 16) { sharesOwned = Portfolio[symbol].Quantity; #region logging SendTransactionsToFile(); #endregion NotifyUser(); } #endregion if (Time.Hour == 15 && Time.Minute > 45) { signal = OrderSignal.doNothing; if (Portfolio[symbol].IsLong) { signal = OrderSignal.goShort; } if (Portfolio[symbol].IsShort) { signal = OrderSignal.goLong; } } } }
public OrderSignal CheckSignal(TradeBars data, IndicatorDataPoint trendCurrent, out string comment) { OrderSignal retval = OrderSignal.doNothing; comment = string.Empty; decimal price = (data[symbol].Close + data[symbol].Open) / 2; trend.Update(idp(data[symbol].EndTime, price)); if (trendCurrent.Value != trend.Current.Value) { comment = "not equal"; } UpdateTrendArray(trend.Current); bReverseTrade = false; v.ReverseTrade = false; v.NTrigGTEP = false; v.NTrigLTEP = false; v.NTrigGTTA0 = false; v.NTrigLTTA0 = false; v.OrderFilled = true; v.IsLong = IsLong; v.IsShort = IsShort; v.BarcountLT4 = false; if (Barcount < 4) { v.BarcountLT4 = true; comment = "Barcount < 4"; retval = OrderSignal.doNothing; } else { nTrig = 2 * trendArray[0] - trendArray[2]; #region "Selection Logic Reversals" try { if (nTrig < (Math.Abs(nEntryPrice) / RevPct)) { v.NTrigLTEP = true; if (IsLong) { retval = OrderSignal.revertToShort; bReverseTrade = true; v.ReverseTrade = true; comment = string.Format("nTrig {0} < (nEntryPrice {1} * RevPct {2}) {3} IsLong {4} )", Math.Round(nTrig, 4), nEntryPrice, RevPct, v.NTrigLTEP, IsLong); } else { v.NTrigLTEP = false; } } else { if (nTrig > (Math.Abs(nEntryPrice) * RevPct)) { v.NTrigGTEP = true; if (IsShort) { retval = OrderSignal.revertToLong; bReverseTrade = true; v.ReverseTrade = true; comment = string.Format("nTrig {0} > (nEntryPrice {1} * RevPct {2}) {3} IsLong {4} )", Math.Round(nTrig, 4), nEntryPrice, RevPct, v.NTrigLTEP, IsLong); } else { v.NTrigGTEP = false; } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion #region "selection logic buy/sell" try { if (!bReverseTrade) { if (nTrig > trendArray[0]) { v.NTrigGTTA0 = true; if (xOver == -1) { if (!IsLong) { if (!orderFilled) { v.OrderFilled = false; retval = OrderSignal.goLong; comment = string.Format( "nTrig {0} > trend {1} xOver {2} !IsLong {3} !orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsLong, !orderFilled); } else { retval = OrderSignal.goLongLimit; comment = string.Format("nTrig {0} > trend {1} xOver {2} !IsLong {3} !orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsLong, !orderFilled); } } } if (comment.Length == 0) { comment = "Trigger over trend - setting xOver to 1"; } xOver = 1; v.xOverisNegative = xOver < 0; v.xOverIsPositive = xOver > 0; } else { if (nTrig < trendArray[0]) { v.NTrigLTTA0 = true; if (xOver == 1) { if (!IsShort) { if (!orderFilled) { v.OrderFilled = false; retval = OrderSignal.goShort; comment = string.Format( "nTrig {0} < trend {1} xOver {2} !isShort {3} orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsShort, !orderFilled); } else { retval = OrderSignal.goShortLimit; comment = string.Format( "nTrig {0} < trend {1} xOver {2} !isShort {3} orderFilled {4}", Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, !IsShort, !orderFilled); } } } if (comment.Length == 0) { comment = "Trigger under trend - setting xOver to -1"; } xOver = -1; v.xOverisNegative = xOver < 0; v.xOverIsPositive = xOver > 0; } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion } StringBuilder sb = new StringBuilder(); sb.Append(comment); sb.Append(","); sb.Append(retval.ToString()); sb.Append(","); sb.Append(v.ToInt32()); sb.Append(","); sb.Append(v.ToIntCsv()); comment = sb.ToString(); return(retval); }
/// <summary> /// Sells out all positions at 15:50, and calculates the profits for the day /// emails the transactions for the day to me /// </summary> /// <param name="data">TradeBars - the data</param> /// <param name="signalInfosMinute"></param> /// <param name="signal">the current OrderSignal</param> /// <returns>false if end of day, true during the day </returns> private void SellOutAtEndOfDay(KeyValuePair<Symbol, TradeBar> data, ref OrderSignal signal) { if (shouldSellOutAtEod) { #region logging if (Time.Hour == 16) { NotifyUser(); signal = OrderSignal.doNothing; } #endregion if (Time.Hour == 15 && Time.Minute > 45) { signal = OrderSignal.doNothing; if (Portfolio[data.Key].IsLong) { signal = OrderSignal.goShort; } if (Portfolio[data.Key].IsShort) { signal = OrderSignal.goLong; } } } }
/// <summary> /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// </summary> /// <param name="data">TradeBars IDictionary object with your stock data</param> public void OnData(TradeBars data) { #region logging comment = string.Empty; tradingDate = this.Time; #endregion barcount++; // Add the history for the bar var time = this.Time; Price.Add(idp(time, (data[symbol].Close + data[symbol].Open) / 2)); // Update the indicators trend.Update(idp(time, Price[0].Value)); trendHistory.Add(CalculateNewTrendHistoryValue(barcount, time, Price, trend)); #region lists #endregion if (barcount > 17) comment = ""; var of = CancelUnfilledLimitOrders(); iTrendStrategy.orderFilled = of; signal = Strategy(data); #region logging sharesOwned = Portfolio[symbol].Quantity; string logmsg = string.Format( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}" + ",{21},{22},{23},{24},{25},{26},{27},{28},{29},{30},{31},{32},{33},{34},{35},{36},{37}", time, barcount, data[symbol].Volume, data[symbol].Open, data[symbol].High, data[symbol].Low, data[symbol].Close, data[symbol].EndTime, data[symbol].Period, data[symbol].DataType, data[symbol].IsFillForward, data[symbol].Time, data[symbol].Symbol, data[symbol].Value, data[symbol].Price, "", time.ToShortTimeString(), Price[0].Value, trend.Current.Value, signals[0], iTrendStrategy.nTrig, iTrendStrategy.orderFilled, iTrendStrategy.nEntryPrice, comment, "", nEntryPrice, nExitPrice, tradeResult, orderId, Portfolio.TotalUnrealisedProfit, sharesOwned, tradeprofit, tradefees, tradenet, Portfolio.TotalPortfolioValue, "", "", "" ); mylog.Debug(logmsg); // reset the trade profit tradeprofit = 0; tradefees = 0; tradenet = 0; #endregion // At the end of day, reset the trend and trendHistory if (time.Hour == 16) { trend.Reset(); trendHistory.Reset(); iTrendStrategy.Reset(); barcount = 0; Plot("Strategy Equity", "Portfolio", Portfolio.TotalPortfolioValue); } }
/// <summary> /// Sells out all positions at 15:50, and calculates the profits for the day /// emails the transactions for the day to me /// </summary> /// <param name="data">TradeBars - the data</param> /// <param name="signalInfosMinute"></param> /// <param name="signal">the current OrderSignal</param> /// <returns>false if end of day, true during the day </returns> private void SellOutAtEndOfDay(KeyValuePair<Symbol, TradeBar> data, ref OrderSignal signal) { if (shouldSellOutAtEod) { //signal = OrderSignal.doNothing; // Just in case a signal slipped through in the last minute. #region logging if (Time.Hour == 16) { #region logging SendTransactionsToFile(data.Key + "transactions.csv"); #endregion //NotifyUser(); } #endregion if (Time.Hour == 15 && Time.Minute > 45) { if (Portfolio[data.Key].IsLong) { signal = OrderSignal.goShort; } if (Portfolio[data.Key].IsShort) { signal = OrderSignal.goLong; } } } }
/// <summary> /// Estimate number of shares, given a kind of operation. /// </summary> /// <param name="symbol">The symbol to operate.</param> /// <param name="order">The kind of order.</param> /// <returns>The signed number of shares given the operation.</returns> public int PositionShares(string symbol, OrderSignal order) { int quantity; int operationQuantity; switch (order) { case OrderSignal.goLong: case OrderSignal.goLongLimit: operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]); quantity = Math.Min(maxOperationQuantity, operationQuantity); break; case OrderSignal.goShort: case OrderSignal.goShortLimit: operationQuantity = CalculateOrderQuantity(symbol, -ShareSize[symbol]); quantity = Math.Max(-maxOperationQuantity, operationQuantity); break; case OrderSignal.closeLong: case OrderSignal.closeShort: quantity = -Portfolio[symbol].Quantity; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: quantity = -2 * Portfolio[symbol].Quantity; break; default: quantity = 0; break; } return quantity; }
/// <summary> /// Run the strategy associated with this algorithm /// </summary> /// <param name="data">TradeBars - the data received by the OnData event</param> private string Strategy(TradeBars data) { #region "Strategy Execution" string ret = ""; if (SellOutEndOfDay(data)) { // if there were limit order tickets to cancel, wait a bar to execute the strategy iTrendStrategy.Barcount = barcount; // for debugging iTrendStrategy.nEntryPrice = nEntryPrice; signal = iTrendStrategy.ExecuteStrategy(data, tradesize, trend.Current, out comment); #region lists #endregion } #endregion return ret; }
/// <summary> /// Executes the Instant Trend strategy /// </summary> /// <param name="data">TradeBars - the current OnData</param> /// <param name="tradesize"></param> /// <param name="trendCurrent">IndicatorDataPoint - the current trend value trend</param> /// <param name="current"></param> public OrderSignal ExecuteStrategy(TradeBars data, int tradesize, IndicatorDataPoint trendCurrent, out string current) { OrderTicket ticket; string comment = string.Empty; OrderSignal retval = OrderSignal.doNothing; trendHistory.Add(trendCurrent); nStatus = 0; if (_algorithm.Portfolio[_symbol].IsLong) { nStatus = 1; } if (_algorithm.Portfolio[_symbol].IsShort) { nStatus = -1; } if (!trendHistory.IsReady) { current = "Trend Not Ready"; return(OrderSignal.doNothing); } #region "Strategy Execution" bReverseTrade = false; try { var nTrig = 2 * trendHistory[0].Value - trendHistory[2].Value; if (nStatus == 1 && nTrig < (Math.Abs(nEntryPrice) / RevPct)) { if (maketrade) { ticket = ReverseToShort(); orderFilled = ticket.OrderId > 0; } bReverseTrade = true; retval = OrderSignal.revertToShort; comment = string.Format("{0} nStatus == {1} && nTrig {2} < (nEntryPrice {3} * RevPct{4} orderFilled {5})", retval, nStatus, nTrig, nEntryPrice, RevPct, orderFilled); } else { if (nStatus == -1 && nTrig > (Math.Abs(nEntryPrice) * RevPct)) { if (maketrade) { ticket = ReverseToLong(); orderFilled = ticket.OrderId > 0; } bReverseTrade = true; retval = OrderSignal.revertToLong; comment = string.Format("{0} nStatus == {1} && nTrig {2} > (nEntryPrice {3} * RevPct{4}, orderFilled {5})", retval, nStatus, nTrig, nEntryPrice, RevPct, orderFilled); } } if (!bReverseTrade) { if (nTrig > trendHistory[0].Value) { if (xOver == -1 && nStatus != 1) { if (!orderFilled) { try { if (maketrade) { ticket = _algorithm.Buy(_symbol, tradesize); } } catch (Exception e) { Console.WriteLine(e); } retval = OrderSignal.goLong; comment = string.Format("{0} nStatus {1} nTrig {2} > trendHistory[0].Value {3} xOver {4} orderFilled {5}", retval, nStatus, nTrig, trendHistory[0].Value, xOver, orderFilled); } else { nLimitPrice = Math.Round(Math.Max(data[_symbol].Low, (data[_symbol].Close - (data[_symbol].High - data[_symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); try { if (maketrade) { ticket = _algorithm.LimitOrder(_symbol, tradesize, nLimitPrice, "Long Limit"); } } catch (Exception e) { Console.WriteLine(e); } retval = OrderSignal.goLongLimit; comment = string.Format("{0} nStatus {1} nTrig {2} > trendHistory[0].Value {3} xOver {4} Limit Price {5}", retval, nStatus, nTrig, trendHistory[0].Value, xOver, nLimitPrice); } } if (comment.Length == 0) { comment = "Trigger over Trend"; } xOver = 1; } else { if (nTrig < trendHistory[0].Value) { if (xOver == 1 && nStatus != -1) { if (!orderFilled) { try { if (maketrade) { ticket = _algorithm.Sell(_symbol, tradesize); } } catch (Exception e) { Console.WriteLine(e); } retval = OrderSignal.goShort; comment = string.Format("{0} Enter Short after cancel trig xunder price down", retval); } else { nLimitPrice = Math.Round(Math.Min(data[_symbol].High, (data[_symbol].Close + (data[_symbol].High - data[_symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); try { if (maketrade) { ticket = _algorithm.LimitOrder(_symbol, -tradesize, nLimitPrice, "Short Limit"); } //ticket = _algorithm.Sell(_symbol, tradesize); } catch (Exception e) { Console.WriteLine(e); } retval = OrderSignal.goShortLimit; comment = string.Format("{0} nStatus {1} nTrig {2} < trendHistory[0].Value {3} xOver {4} Limit Price {5}", retval, nStatus, nTrig, trendHistory[0].Value, xOver, nLimitPrice); } } if (comment.Length == 0) { comment = "Trigger under trend"; } xOver = -1; } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion current = comment; return(retval); }
private OrderSignal CheckLossThreshhold(ref string comment, OrderSignal retval) { //if (Barcount >= 376) // System.Diagnostics.Debug.WriteLine("Barcount: " + Barcount); if (UnrealizedProfit < _lossThreshhold) { if (IsLong) { retval = OrderSignal.goShortLimit; } if (IsShort) { retval = OrderSignal.goLongLimit; } comment = string.Format("Unrealized loss exceeded {0}", _lossThreshhold); bReverseTrade = true; } return retval; }
public int? PositionShares(string symbol, OrderSignal order, int? maxShares = null, decimal? maxAmount = null, decimal? maxPortfolioShare = null) { int? quantity; int operationQuantity; switch (order) { case OrderSignal.goLong: operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]); quantity = operationQuantity; break; case OrderSignal.goShort: operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]); quantity = -operationQuantity; break; default: quantity = null; break; } return quantity; }
public void OnData(TradeBars data) { barCounter++; // just for debug #region logging comment = string.Empty; tradingDate = this.Time; #endregion bool isMarketAboutToClose = !theMarket.DateTimeIsOpen(Time.AddMinutes(10)); OrderSignal actualOrder = OrderSignal.doNothing; int i = 0; foreach (string symbol in Symbols) { // Operate only if the market is open if (theMarket.DateTimeIsOpen(Time)) { // First check if there are some limit orders not filled yet. if (Transactions.LastOrderId > 0) { CheckLimitOrderStatus(symbol, data); } // Check if the market is about to close and noOvernight is true. if (noOvernight && isMarketAboutToClose) { actualOrder = ClosePositions(symbol); } else { // Now check if there is some signal and execute the strategy. actualOrder = Strategy[symbol].ActualSignal; } ExecuteStrategy(symbol, actualOrder); sharesOwned = Portfolio[symbol].Quantity; } #region Logging stuff - Filling the data StockLogging //"Counter, Time, Close, ITrend, Trigger," + //"Momentum, EntryPrice, Signal," + //"TriggerCrossOverITrend, TriggerCrossUnderITrend, ExitFromLong, ExitFromShort," + //"StateFromStrategy, StateFromPorfolio, Portfolio Value" string newLine = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14}", barCounter, Time, (data[symbol].Close + data[symbol].Open) / 2, Strategy[symbol].ITrend.Current.Value, Strategy[symbol].ITrend.Current.Value + Strategy[symbol].ITrendMomentum.Current.Value, Strategy[symbol].ITrendMomentum.Current.Value, (Strategy[symbol].EntryPrice == null) ? 0 : Strategy[symbol].EntryPrice, actualOrder, Strategy[symbol].TriggerCrossOverITrend.ToString(), Strategy[symbol].TriggerCrossUnderITrend.ToString(), Strategy[symbol].ExitFromLong.ToString(), Strategy[symbol].ExitFromShort.ToString(), Strategy[symbol].Position.ToString(), Portfolio[symbol].Quantity.ToString(), Portfolio.TotalPortfolioValue ); stockLogging[i].AppendLine(newLine); i++; #endregion Logging stuff - Filling the data StockLogging #region "biglog" string logmsg = string.Format( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}" + ",{21},{22},{23},{24},{25},{26},{27},{28},{29},{30},{31},{32}", symbol, data[symbol].EndTime, barCounter, data[symbol].Volume, data[symbol].Open, data[symbol].High, data[symbol].Low, data[symbol].Close, "", "", data[symbol].EndTime.ToShortTimeString(), data[symbol].Close, Strategy[symbol].ITrend.Current.Value, "", Strategy[symbol].ActualSignal, comment, "", Strategy[symbol].EntryPrice ?? 0, "", Portfolio.TotalUnrealisedProfit, "", sharesOwned, "", Portfolio.TotalPortfolioValue, "", "", "", "", "", "", "", "", "" ); mylog.Debug(logmsg); //tradeprofit = 0; //tradefees = 0; //tradenet = 0; #endregion } if (tradingDate.Hour == 16) { barCounter = 0; } }
/// <summary> /// Executes the strategy. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualOrder">The actual order.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder) { int? shares = PositionShares(symbol, actualOrder); switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: // If the returned shares is null then is the same than doNothing. if (shares.HasValue) { Log("===> Market entry order sent " + symbol); MarketOrder(symbol, shares.Value); } break; case OrderSignal.closeLong: case OrderSignal.closeShort: Log("<=== Closing Position " + symbol); MarketOrder(symbol, shares.Value); break; default: break; } }
/// <summary> /// Estimate number of shares, given a kind of operation. /// </summary> /// <param name="symbol">The symbol to operate.</param> /// <param name="order">The kind of order.</param> /// <returns>The signed number of shares given the operation.</returns> public int PositionShares(Symbol symbol, OrderSignal order) { int quantity; int operationQuantity; decimal targetSize; targetSize = GetBetSize(symbol); switch (order) { case OrderSignal.goLongLimit: case OrderSignal.goLong: //operationQuantity = CalculateOrderQuantity(symbol, targetSize); // let the algo decide on order quantity operationQuantity = (int)targetSize; quantity = Math.Min(maxOperationQuantity, operationQuantity); break; case OrderSignal.goShortLimit: case OrderSignal.goShort: //operationQuantity = CalculateOrderQuantity(symbol, targetSize); // let the algo decide on order quantity operationQuantity = (int)targetSize; quantity = -Math.Min(maxOperationQuantity, operationQuantity); break; case OrderSignal.closeLong: case OrderSignal.closeShort: quantity = -Portfolio[symbol].Quantity; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: quantity = -2 * Portfolio[symbol].Quantity; break; default: quantity = 0; break; } return quantity; }
public void RealDataTest2() { // Almost the same test, but in this case, the strategy should send a doNothing instead a repeated goShort. int _trendPeriod = 5; int _invFisherPeriod = 6; decimal _tolerance = 0.001m; decimal _threshold = 0.9m; DateTime time = DateTime.Now; # region Arrays inputs // Real AMZN minute data decimal[] prices = new decimal[30] { 428.78m, 428.79m, 428.72m, 428.67m, 428.66m, 428.62m, 428.83m, 428.89m, 428.85m, 428.78m, 428.77m, 429.29m, 429.53m, 429.33m, 429.30m, 429.04m, 429.29m, 428.90m, 428.88m, 429.07m, 429.03m, 429.35m, 429.42m, 429.75m, 430.43m, 430.33m, 430.52m, 430.41m, 430.22m, 430.25m }; OrderSignal[] expectedOrders = new OrderSignal[30] { OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goShort , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.closeShort, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goShort }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; Identity VoidIndicator = new Identity("Void"); DIFStrategy strategy = new DIFStrategy(VoidIndicator, _trendPeriod, _invFisherPeriod, _threshold, _tolerance); for (int i = 0; i < prices.Length; i++) { strategy.DecycleTrend.Update(new IndicatorDataPoint(time, prices[i])); strategy.InverseFisher.Update(strategy.DecycleTrend.Current); actualOrders[i] = strategy.ActualSignal; if (actualOrders[i] == OrderSignal.goShort && strategy.Position == StockState.noInvested) strategy.Position = StockState.shortPosition; if (actualOrders[i] == OrderSignal.closeShort && strategy.Position == StockState.shortPosition) strategy.Position = StockState.noInvested; if (actualOrders[i] == OrderSignal.goLong && strategy.Position == StockState.noInvested) strategy.Position = StockState.longPosition; if (actualOrders[i] == OrderSignal.closeLong && strategy.Position == StockState.longPosition) strategy.Position = StockState.noInvested; Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); Console.WriteLine(strategy.DecycleTrend.Current.ToString()); Console.WriteLine(strategy.InverseFisher.Current.ToString() + "\n"); time = time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
private void OnDataForSymbol(KeyValuePair <Symbol, TradeBar> data) { #region logging comment = string.Empty; tradingDate = this.Time; #endregion barcount++; var time = this.Time; List <SignalInfo> minuteSignalInfos = new List <SignalInfo>(signalInfos.Where(s => s.Name == data.Key)); if (minuteSignalInfos.Any()) { foreach (var signalInfo in minuteSignalInfos) { signalInfo.Price.Add(idp(time, (data.Value.Close + data.Value.Open) / 2)); // Update the indicators signalInfo.trend.Update(idp(time, signalInfo.Price[0].Value)); } // Get the OrderSignal from the Sig9 GetOrderSignals(data, minuteSignalInfos); foreach (var currentSignalInfo in minuteSignalInfos) { // If EOD, set signal to sell/buy out. OrderSignal signal = currentSignalInfo.Value; SellOutAtEndOfDay(data, ref signal); currentSignalInfo.Value = signal; if (currentSignalInfo.Status == OrderStatus.Submitted) { HandleSubmitted(data, currentSignalInfo); } if (currentSignalInfo.Status == OrderStatus.PartiallyFilled) { HandlePartiallyFilled(data, currentSignalInfo); } if (currentSignalInfo.Value != OrderSignal.doNothing && currentSignalInfo.IsActive) { // set now because MarketOrder fills can happen before ExecuteStrategy returns. currentSignalInfo.Status = OrderStatus.New; currentSignalInfo.IsActive = false; ExecuteStrategy(currentSignalInfo.Symbol, currentSignalInfo, data); } } } var sharesOwned = Portfolio[data.Key].Quantity; #region "logging" string logmsg = string.Format( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20}" + ",{21},{22},{23},{24},{25},{26},{27},{28},{29},{30},{31},{32},{33},{34},{35},{36},{37},{38},{39}", time, barcount, data.Value.Volume, data.Value.Open, data.Value.High, data.Value.Low, data.Value.Close, data.Value.EndTime, data.Value.Period, data.Value.DataType, data.Value.IsFillForward, data.Value.Time, data.Value.Symbol, data.Value.Value, "", "", time.ToShortTimeString(), signalInfos[0].Price[0].Value, signalInfos[0].trend.Current.Value, signalInfos[0].nTrig, signalInfos[0].Value, comment, "", nEntryPrice, signalInfos[0].IsActive, Portfolio.TotalUnrealisedProfit, orderId, sharesOwned, tradenet, Portfolio.TotalPortfolioValue, "", "", "", "", "", "", "", "", "", "" ); //mylog.Debug(logmsg); #endregion tradeprofit = 0; tradefees = 0; tradenet = 0; // At the end of day, reset the trend and trendHistory if (time.Hour == 16) { barcount = 0; } }
public void ToleranceTesting() { // This is the same GoLongAndClosePosition Test, only the tolerance is increased to avoid signals. int _trendPeriod = 5; int _invFisherPeriod = 6; decimal _tolerance = 2m; decimal _threshold = 0.9m; DateTime time = DateTime.Now; # region Arrays inputs decimal[] prices = new decimal[15] { 24.51m, 24.51m, 20.88m, 15m, 9.12m, 5.49m, 5.49m, 9.12m, 15m, 20.88m, 24.51m, 24.51m, 20.88m, 15m, 9.12m, }; OrderSignal[] expectedOrders = new OrderSignal[15] { OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; Identity VoidIndicator = new Identity("Void"); DIFStrategy strategy = new DIFStrategy(VoidIndicator, _trendPeriod, _invFisherPeriod, _threshold, _tolerance); for (int i = 0; i < prices.Length; i++) { strategy.DecycleTrend.Update(new IndicatorDataPoint(time, prices[i])); strategy.InverseFisher.Update(strategy.DecycleTrend.Current); actualOrders[i] = strategy.ActualSignal; if (actualOrders[i] == OrderSignal.goLong) strategy.Position = StockState.longPosition; Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual arder to be execute.</param> /// <param name="data">The actual TradeBar data.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder, TradeBars data) { int shares; decimal limitPrice = 0m; switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Define the limit price. ( Nick added the rounding to avoid invalid limit orders) if (actualOrder == OrderSignal.goLong) { limitPrice = Math.Round(Math.Max(data[symbol].Low, (data[symbol].Close - (data[symbol].High - data[symbol].Low) * RngFac))); } else if (actualOrder == OrderSignal.goShort) { limitPrice = Math.Round(Math.Min(data[symbol].High, (data[symbol].Close + (data[symbol].High - data[symbol].Low) * RngFac))); } // Send the order. Tickets[symbol].Add(LimitOrder(symbol, shares, limitPrice)); // Update the LastOrderSent dictionary. LastOrderSent[symbol] = actualOrder; break; case OrderSignal.closeLong: case OrderSignal.closeShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. Tickets[symbol].Add(MarketOrder(symbol, shares)); // Because the order is an synchronously market order, they'll fill // inmediatelly. So, update the ITrend strategy and the LastOrder Dictionary. Strategy[symbol].Position = StockState.noInvested; Strategy[symbol].EntryPrice = null; LastOrderSent[symbol] = OrderSignal.doNothing; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. Tickets[symbol].Add(MarketOrder(symbol, shares)); // Beacuse the order is an synchronously market order, they'll fill // inmediatlly. So, update the ITrend strategy and the LastOrder Dictionary. if (actualOrder == OrderSignal.revertToLong) Strategy[symbol].Position = StockState.longPosition; else if (actualOrder == OrderSignal.revertToShort) Strategy[symbol].Position = StockState.shortPosition; Strategy[symbol].EntryPrice = Tickets[symbol].Last().AverageFillPrice; LastOrderSent[symbol] = actualOrder; break; default: break; } }
/// <summary> /// Estimates the shares quantity for the next operation. It returns the quantity SIGNED /// depending on the actualSignal i.e. positive if buy, negative if sell /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualSignal">The actual signal.</param> /// <returns></returns> private int? EstimatePosition(string symbol, OrderSignal actualSignal) { int marginAvailable; int quantity; int? operationQuantity = null; // Make the estimations only if the orders are to entry in the market. if (actualSignal == OrderSignal.goLong || actualSignal == OrderSignal.goShort) { // Check the margin and the quantity to achieve target-percent holdings then choose the minimum. marginAvailable = (int)Math.Floor(Portfolio.MarginRemaining / Securities[symbol].Price); quantity = Math.Min(CalculateOrderQuantity(symbol, shareSize), marginAvailable); // Only assign a value to the operationQuantity if is bigger than a threshold. if (quantity > 10) { // Make the quantity signed accord to the order. operationQuantity = actualSignal == OrderSignal.goLong ? quantity : -quantity; } } return operationQuantity; }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual arder to be execute.</param> /// <param name="data">The actual TradeBar data.</param> private void ExecuteStrategy(string symbol, decimal entryPrice, OrderSignal actualOrder, TradeBars data) { int shares; decimal limitPrice = 0m; switch (actualOrder) { case OrderSignal.goLong: shares = PositionShares(symbol, actualOrder); Tickets[symbol].Add(MarketOrder(symbol, shares)); Strategy[symbol].Position = StockState.shortPosition; Strategy[symbol].nEntryPrice = entryPrice; LastOrderSent[symbol] = actualOrder; break; case OrderSignal.goShort: shares = PositionShares(symbol, actualOrder); Tickets[symbol].Add(MarketOrder(symbol, shares)); Strategy[symbol].Position = StockState.longPosition; Strategy[symbol].nEntryPrice = entryPrice; LastOrderSent[symbol] = actualOrder; break; case OrderSignal.goLongLimit: shares = PositionShares(symbol, actualOrder); // Define the limit price. //limitPrice = Math.Max(data[symbol].Low, (data[symbol].Close - (data[symbol].High - data[symbol].Low) * RngFac)); limitPrice = Math.Round(Math.Max(data[symbol].Low, (data[symbol].Close - (data[symbol].High - data[symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); // Send the order. Tickets[symbol].Add(LimitOrder(symbol, shares, limitPrice)); // Update the LastOrderSent dictionary. LastOrderSent[symbol] = actualOrder; break; case OrderSignal.goShortLimit: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Define the limit price. //limitPrice = Math.Min(data[symbol].High, (data[symbol].Close + (data[symbol].High - data[symbol].Low) * RngFac)); limitPrice = Math.Round(Math.Min(data[symbol].High, (data[symbol].Close + (data[symbol].High - data[symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); // Send the order. var security = Securities[symbol]; ProformaOrderTicket x = _brokerSimulator.LimitOrder(symbol, shares, limitPrice); Tickets[symbol].Add(LimitOrder(symbol, shares, limitPrice)); // Update the LastOrderSent dictionary. LastOrderSent[symbol] = actualOrder; break; case OrderSignal.closeLong: case OrderSignal.closeShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. Tickets[symbol].Add(MarketOrder(symbol, shares)); // Because the order is an synchronously market order, they'll fill // immediately. So, update the ITrend strategy and the LastOrder Dictionary. Strategy[symbol].Position = StockState.noInvested; Strategy[symbol].nEntryPrice = entryPrice; LastOrderSent[symbol] = OrderSignal.doNothing; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. Tickets[symbol].Add(MarketOrder(symbol, shares)); // Beacuse the order is an synchronously market order, they'll fill // immediately. So, update the ITrend strategy and the LastOrder Dictionary. if (actualOrder == OrderSignal.revertToLong) { Strategy[symbol].Position = StockState.longPosition; } else if (actualOrder == OrderSignal.revertToShort) { Strategy[symbol].Position = StockState.shortPosition; } Strategy[symbol].nEntryPrice = Tickets[symbol].Last().AverageFillPrice; LastOrderSent[symbol] = actualOrder; break; default: break; } }
public OrderSignal CheckSignal(TradeBars data, IndicatorDataPoint trendCurrent, out string comment) { OrderSignal retval = OrderSignal.doNothing; if (Barcount == 1) { comment = ""; } decimal price = (data[symbol].Close + data[symbol].Open) / 2; trend.Update(idp(data[symbol].EndTime, price)); if (trendCurrent.Value != trend.Current.Value) { comment = "not equal"; } UpdateTrendArray(trend.Current); comment = ""; bReverseTrade = false; if (Barcount < 4) { comment = "Trend Not Ready"; return(OrderSignal.doNothing); } #region "Selection Logic Reversals" try { nTrig = 2 * trendArray[0] - trendArray[2]; // Note this is backwards from a RollingWindow if (IsLong && nTrig < (Math.Abs(nEntryPrice) / RevPct)) { retval = OrderSignal.revertToShort; bReverseTrade = true; comment = string.Format("{0} nTrig {1} < (nEntryPrice {2} * RevPct{3}) orderFilled {4})", retval, Math.Round(nTrig, 4), nEntryPrice, RevPct, orderFilled); } else { if (IsShort && nTrig > (Math.Abs(nEntryPrice) * RevPct)) { retval = OrderSignal.revertToLong; bReverseTrade = true; comment = string.Format("{0} nTrig {1} > (nEntryPrice {2} * RevPct{3}) orderFilled {4})", retval, Math.Round(nTrig, 4), nEntryPrice, RevPct, orderFilled); } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion #region "selection logic buy/sell" try { if (!bReverseTrade) { if (nTrig > trendArray[0]) { if (xOver == -1 && !IsLong) { if (!orderFilled) { retval = OrderSignal.goLong; comment = string.Format( "{0} IsLong && nTrig {1} > trend {2} xOver {3} orderFilled {4}", retval, Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, orderFilled); } else { retval = OrderSignal.goLongLimit; comment = string.Format( "{0} IsLong && nTrig {1} > trend {2} xOver {3}", retval, Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver); } } if (comment.Length == 0) { comment = "Trigger over trend - setting xOver to 1"; } xOver = 1; } else { if (nTrig < trendArray[0]) { if (xOver == 1 && !IsShort) { if (!orderFilled) { retval = OrderSignal.goShort; comment = string.Format( "{0} nTrig {1} < trend {2} xOver {3} orderFilled {4}", retval, Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver, orderFilled); } else { retval = OrderSignal.goShortLimit; comment = string.Format( "{0} nTrig {1} < trend {2} xOver {3}", retval, Math.Round(nTrig, 4), Math.Round(trendArray[0], 4), xOver); } } if (comment.Length == 0) { comment = "Trigger under trend - setting xOver to -1"; } xOver = -1; } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion return(retval); }
public void RealDataTest() { int _trendPeriod = 5; int _invFisherPeriod = 6; decimal _tolerance = 0.001m; decimal _threshold = 0.9m; DateTime time = DateTime.Now; # region Arrays inputs // Real AMZN minute data decimal[] prices = new decimal[30] { 427.30m, 427.24m, 427.57m, 427.71m, 427.59m, 427.95m, 427.27m, 427.19m, 427.45m, 427.81m, 427.62m, 427.66m, 427.67m, 427.62m, 427.67m, 427.20m, 426.89m, 427.27m, 427.46m, 427.31m, 427.11m, 427.29m, 427.54m, 427.87m, 427.80m, 427.35m, 427.34m, 427.75m, 427.94m, 429.00m, }; OrderSignal[] expectedOrders = new OrderSignal[30] { OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goShort , OrderSignal.doNothing , OrderSignal.closeShort, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.doNothing , OrderSignal.goShort, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.closeShort, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.doNothing , OrderSignal.doNothing , OrderSignal.doNothing, OrderSignal.doNothing, OrderSignal.goShort , OrderSignal.closeShort, OrderSignal.doNothing , OrderSignal.doNothing }; # endregion OrderSignal[] actualOrders = new OrderSignal[expectedOrders.Length]; Identity VoidIndicator = new Identity("Void"); DIFStrategy strategy = new DIFStrategy(VoidIndicator, _trendPeriod, _invFisherPeriod, _threshold, _tolerance); for (int i = 0; i < prices.Length; i++) { strategy.DecycleTrend.Update(new IndicatorDataPoint(time, prices[i])); strategy.InverseFisher.Update(strategy.DecycleTrend.Current); actualOrders[i] = strategy.ActualSignal; if (actualOrders[i] == OrderSignal.goShort && strategy.Position == StockState.noInvested) strategy.Position = StockState.shortPosition; if (actualOrders[i] == OrderSignal.closeShort && strategy.Position == StockState.shortPosition) strategy.Position = StockState.noInvested; if (actualOrders[i] == OrderSignal.goLong && strategy.Position == StockState.noInvested) strategy.Position = StockState.longPosition; if (actualOrders[i] == OrderSignal.closeLong && strategy.Position == StockState.longPosition) strategy.Position = StockState.noInvested; Console.WriteLine(i + "| Actual Order:" + actualOrders[i]); Console.WriteLine(strategy.DecycleTrend.Current.ToString()); Console.WriteLine(strategy.InverseFisher.Current.ToString() + "\n"); time = time.AddDays(1); } Assert.AreEqual(expectedOrders, actualOrders); }
/// <summary> /// Executes the strategy. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="actualOrder">The actual order.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder) { int? shares; switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. if (shares.HasValue) { Log("===> Market entry order sent " + symbol); int orderShares = shares.Value; var entryOrder = MarketOrder(symbol, orderShares); // submit stop loss order for max loss on the trade decimal stopPrice = (actualOrder == OrderSignal.goLong) ? Securities[symbol].Low * (1 - GlobalStopLossPercent) : Securities[symbol].High * (1 + GlobalStopLossPercent); StopLossTickets[symbol] = StopMarketOrder(symbol, -orderShares, stopPrice); EnablePsarTrailingStop[symbol] = false; } break; case OrderSignal.closeLong: case OrderSignal.closeShort: Log("<=== Liquidate " + symbol); Liquidate(symbol); StopLossTickets[symbol].Cancel(); StopLossTickets[symbol] = null; break; default: break; } }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual order to be execute.</param> /// <param name="data">The actual TradeBar data.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder) { // Define the operation size. int shares = PositionShares(symbol, actualOrder); switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: case OrderSignal.goLongLimit: case OrderSignal.goShortLimit: Log("===> Entry to Market"); decimal limitPrice; var barPrices = Securities[symbol]; // Define the limit price. if (actualOrder == OrderSignal.goLong || actualOrder == OrderSignal.goLongLimit) { limitPrice = Math.Max(barPrices.Low, (barPrices.Close - (barPrices.High - barPrices.Low) * RngFac)); } else { limitPrice = Math.Min(barPrices.High, (barPrices.Close + (barPrices.High - barPrices.Low) * RngFac)); } // Send the order. LimitOrder(symbol, shares, limitPrice); break; case OrderSignal.closeLong: case OrderSignal.closeShort: Log("<=== Closing Position"); // Send the order. MarketOrder(symbol, shares); break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: Log("<===> Reverting Position"); // Send the order. MarketOrder(symbol, shares); break; default: break; } }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual order to be execute.</param> private void ExecuteStrategy(string symbol, OrderSignal actualOrder) { // Define the operation size. PositionShares can sometimes return 0 // if your position gets overextended. // If that happens the code avoids an invalid order, by just returning. int shares = PositionShares(symbol, actualOrder); if (shares == 0) { Strategy[symbol].IsActive = true; return; } switch (actualOrder) { case OrderSignal.goLong: case OrderSignal.goShort: case OrderSignal.goLongLimit: case OrderSignal.goShortLimit: //Log("===> Entry to Market"); decimal limitPrice; var barPrices = Securities[symbol]; // Define the limit price. if (actualOrder == OrderSignal.goLong || actualOrder == OrderSignal.goLongLimit) { limitPrice = Math.Max(barPrices.Low, (barPrices.Close - (barPrices.High - barPrices.Low) * RngFac)); } else { limitPrice = Math.Min(barPrices.High, (barPrices.Close + (barPrices.High - barPrices.Low) * RngFac)); } // Send the order. LimitOrder(symbol, shares, limitPrice); break; case OrderSignal.closeLong: case OrderSignal.closeShort: //Log("<=== Closing Position"); // Send the order. var ticket = MarketOrder(symbol, shares); break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: //Log("<===> Reverting Position"); // Send the order. MarketOrder(symbol, shares); break; default: break; } }
//public OrderSignal CheckSignal(TradeBars data, int tradesize, IndicatorDataPoint trendCurrent, out string current) //{ // return CheckSignal(data, tradesize, out current, TODO); //} /// <summary> /// Executes the Instant Trend strategy /// </summary> /// <param name="data">TradeBars - the current OnData</param> /// <param name="data">TradeBars - the current OnData</param> /// <param name="tradesize"></param> /// <param name="tradesize"></param> /// <param name="current"></param> /// <param name="current"></param> /// <param name="xOver1"></param> /// <param name="trendCurrent">IndicatorDataPoint - the current trend value trend</param> /// <summary> /// Executes the Instant Trend strategy /// </summary> public OrderSignal CheckSignal(TradeBars data, int tradesize, IndicatorDataPoint trendCurrent, out string current) { OrderTicket ticket; int orderId = 0; string comment = string.Empty; OrderSignal retval = OrderSignal.doNothing; trendHistory.Add(trendCurrent); nStatus = 0; if (_algorithm.Portfolio[_symbol].IsLong) { nStatus = 1; } if (_algorithm.Portfolio[_symbol].IsShort) { nStatus = -1; } if (!trendHistory.IsReady) { current = "Trend Not Ready"; return(OrderSignal.doNothing); } #region "Strategy Execution" bReverseTrade = false; try { var nTrig = 2 * trendHistory[0].Value - trendHistory[2].Value; if (nStatus == 1 && nTrig < (nEntryPrice / RevPct)) { comment = string.Format("Long Reverse to short. Close < {0} / {1}", nEntryPrice, RevPct); bReverseTrade = true; retval = OrderSignal.revertToShort; } else { if (nStatus == -1 && nTrig > (nEntryPrice * RevPct)) { comment = string.Format("Short Reverse to Long. Close > {0} * {1}", nEntryPrice, RevPct); bReverseTrade = true; retval = OrderSignal.revertToLong; } } if (!bReverseTrade) { if (nTrig > trendHistory[0].Value) { if (xOver == -1 && nStatus != 1) { if (!orderFilled) { retval = OrderSignal.goLong; comment = string.Format("{0} after order not filled", retval); } else { nLimitPrice = Math.Round(Math.Max(data[_symbol].Low, (data[_symbol].Close - (data[_symbol].High - data[_symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); retval = OrderSignal.goLongLimit; comment = string.Format("{0} nTrig > history[0] xOver {1} Limit Price {2}", retval, xOver, nLimitPrice); } } if (comment.Length == 0) { comment = "Trigger over Trend"; } xOver = 1; } else { if (nTrig < trendHistory[0].Value) { if (xOver == 1 && nStatus != -1) { if (!orderFilled) { retval = OrderSignal.goShort; comment = string.Format("{0} after order not filled", retval); } else { nLimitPrice = Math.Round(Math.Min(data[_symbol].High, (data[_symbol].Close + (data[_symbol].High - data[_symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); retval = OrderSignal.goShortLimit; comment = string.Format("{0} nTrig < history[0] xOver = {1} Limit Price {2}", retval, xOver, nLimitPrice); } } if (comment.Length == 0) { comment = "Trigger under trend"; } xOver = -1; } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion current = comment; return(retval); }
/// <summary> /// Executes the ITrend strategy orders. /// </summary> /// <param name="symbol">The symbol to be traded.</param> /// <param name="actualOrder">The actual arder to be execute.</param> /// <param name="data">The actual TradeBar data.</param> private void ExecuteStrategy(string symbol, decimal entryPrice, OrderSignal actualOrder, TradeBars data) { int shares; decimal limitPrice = 0m; switch (actualOrder) { case OrderSignal.goLong: shares = PositionShares(symbol, actualOrder); Tickets[symbol].Add(MarketOrder(symbol, shares)); Strategy[symbol].Position = StockState.shortPosition; Strategy[symbol].nEntryPrice = entryPrice; LastOrderSent[symbol] = actualOrder; break; case OrderSignal.goShort: shares = PositionShares(symbol, actualOrder); Tickets[symbol].Add(MarketOrder(symbol, shares)); Strategy[symbol].Position = StockState.longPosition; Strategy[symbol].nEntryPrice = entryPrice; LastOrderSent[symbol] = actualOrder; break; case OrderSignal.goLongLimit: shares = PositionShares(symbol, actualOrder); // Define the limit price. //limitPrice = Math.Max(data[symbol].Low, (data[symbol].Close - (data[symbol].High - data[symbol].Low) * RngFac)); limitPrice = Math.Round(Math.Max(data[symbol].Low, (data[symbol].Close - (data[symbol].High - data[symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); // Send the order. Tickets[symbol].Add(LimitOrder(symbol, shares, limitPrice)); // Update the LastOrderSent dictionary. LastOrderSent[symbol] = actualOrder; break; case OrderSignal.goShortLimit: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Define the limit price. //limitPrice = Math.Min(data[symbol].High, (data[symbol].Close + (data[symbol].High - data[symbol].Low) * RngFac)); limitPrice = Math.Round(Math.Min(data[symbol].High, (data[symbol].Close + (data[symbol].High - data[symbol].Low) * RngFac)), 2, MidpointRounding.ToEven); // Send the order. var security = Securities[symbol]; ProformaOrderTicket x = _brokerSimulator.LimitOrder(symbol, shares, limitPrice); Tickets[symbol].Add(LimitOrder(symbol, shares, limitPrice)); // Update the LastOrderSent dictionary. LastOrderSent[symbol] = actualOrder; break; case OrderSignal.closeLong: case OrderSignal.closeShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. Tickets[symbol].Add(MarketOrder(symbol, shares)); // Because the order is an synchronously market order, they'll fill // immediately. So, update the ITrend strategy and the LastOrder Dictionary. Strategy[symbol].Position = StockState.noInvested; Strategy[symbol].nEntryPrice = entryPrice; LastOrderSent[symbol] = OrderSignal.doNothing; break; case OrderSignal.revertToLong: case OrderSignal.revertToShort: // Define the operation size. shares = PositionShares(symbol, actualOrder); // Send the order. Tickets[symbol].Add(MarketOrder(symbol, shares)); // Beacuse the order is an synchronously market order, they'll fill // immediately. So, update the ITrend strategy and the LastOrder Dictionary. if (actualOrder == OrderSignal.revertToLong) Strategy[symbol].Position = StockState.longPosition; else if (actualOrder == OrderSignal.revertToShort) Strategy[symbol].Position = StockState.shortPosition; Strategy[symbol].nEntryPrice = Tickets[symbol].Last().AverageFillPrice; LastOrderSent[symbol] = actualOrder; break; default: break; } }