/// <summary> /// Simulate a day in the market. /// </summary> public void Simulate() { if (CurrentDate != EndDate) { CurrentDate = CurrentDate.AddDays(1); StockDay = DataManager.IsStockDay(CurrentDate); // before we even bother with any calculations, we need to // make sure the stock market was open on this given day if (StockDay) { UpdateMarketState(); StockDays.Add(CurrentDate); Log("Stockday on " + CurrentDate + ", proceeding..."); // how has our equity changed over postmarket and premarket for (int i = 0; i < Positions.Count; i++) { List <BarData> history = MarketState.FirstOrDefault(x => x.Key == Positions[i].Symbol).Value; // how much has the stock changed in value overnight? double change = history.Last().Open - history[history.Count - 2].Close; // change our equity! Equity += change * Positions[i].Shares; } // process orders ProcessAllOrders(); // with our new positions, how will our equity change today? for (int i = 0; i < Positions.Count; i++) { List <BarData> history = MarketState.FirstOrDefault(x => x.Key == Positions[i].Symbol).Value; // how much has the stock changed in value overnight? double change = history.Last().Close - history.Last().Open; // change our equity! Equity += change * Positions[i].Shares; // update the position value Positions[i].PriceHistory.Add(new Tuple <DateTime, double, double>(CurrentDate, history.Last().Close, change)); } // allow the strategy to make calls for the next day Strategy.Update(this); // process all logs for the day ProcessLogs(); } EquityHistory.Add(new Tuple <DateTime, double>(CurrentDate, Equity)); BuyingPowerHistory.Add(new Tuple <DateTime, double>(CurrentDate, BuyingPower)); } else { throw new Exception("Simulation is already complete."); } }
/// <summary> /// Processes orders and box orders. /// </summary> private void ProcessAllOrders() { // now, what orders were placed overnight? for (int i = 0; i < Orders.Count; i++) { List <BarData> history = MarketState.FirstOrDefault(x => x.Key == Orders[i].Symbol).Value; if (Orders[i].ActionType == ActionType.Buy) { if (Orders[i].OrderType == OrderType.Limit) { double realBuyPrice = -1; // has the stocks price gone over or below the limit price today? if (history.Last().High >= Orders[i].LimitPrice && history.Last().Low <= Orders[i].LimitPrice) { realBuyPrice = Orders[i].LimitPrice; } else if (Orders[i].LimitPrice <history.Last().Open&& Orders[i].LimitPrice> history[history.Count - 2].High) { realBuyPrice = history.Last().Open; } else if (Orders[i].LimitPrice > history.Last().Open&& Orders[i].LimitPrice < history[history.Count - 2].Low) { realBuyPrice = history.Last().Open; } if (realBuyPrice != -1) { // if so, can we afford to buy this many shares? if (Orders[i].LimitPrice * Orders[i].Shares <= BuyingPower) { // buy the shares! BuyingPower -= realBuyPrice * Orders[i].Shares; // place a position Positions.Add(new Position(Orders[i].Symbol, Orders[i].Shares, realBuyPrice, CurrentDate)); // fire event Strategy.ProcessOrder(this, Orders[i], realBuyPrice); // log Log("Bought " + Orders[i].Shares + " shares of " + Orders[i].Symbol + " for $" + realBuyPrice + " per share."); // remove this order Orders.Remove(Orders[i]); } } } else if (Orders[i].OrderType == OrderType.Market) { if (history.Last().Open *Orders[i].Shares <= BuyingPower) { // buy the shares! BuyingPower -= history.Last().Open *Orders[i].Shares; // place a position Positions.Add(new Position(Orders[i].Symbol, Orders[i].Shares, history.Last().Open, CurrentDate)); // fire event Strategy.ProcessOrder(this, Orders[i], history.Last().Open); // log Log("Bought " + Orders[i].Shares + " shares of " + Orders[i].Symbol + " for $" + history.Last().Open + " per share."); // remove this order Orders.Remove(Orders[i]); } } } else if (Orders[i].ActionType == ActionType.Sell) { if (Orders[i].OrderType == OrderType.Limit) { double realSellPrice = -1; // has the stocks price gone over or below the limit price today? if (history.Last().High >= Orders[i].LimitPrice && history.Last().Low <= Orders[i].LimitPrice) { realSellPrice = Orders[i].LimitPrice; } else if (Orders[i].LimitPrice <history.Last().Open&& Orders[i].LimitPrice> history[history.Count - 2].High) { realSellPrice = history.Last().Open; } else if (Orders[i].LimitPrice > history.Last().Open&& Orders[i].LimitPrice < history[history.Count - 2].Low) { realSellPrice = history.Last().Open; } if (realSellPrice != -1) { // sell the shares! BuyingPower += realSellPrice * Orders[i].Shares; Equity += (realSellPrice - history.Last().Open) * Orders[i].Shares; int toRemove = Orders[i].Shares; List <Position> positionsToRemove = new List <Position>(); // remove the position for (int j = 0; j < Positions.Count; j++) { if (Positions[j].Symbol == Orders[i].Symbol) { if (Positions[j].BuyPrice >= realSellPrice) { Losses++; } else { Wins++; } if (Positions[j].Shares > toRemove) { Positions[j].Shares -= toRemove; break; } else if (Positions[j].Shares == toRemove) { positionsToRemove.Add(Positions[j]); break; } else if (Positions[j].Shares < toRemove) { positionsToRemove.Add(Positions[j]); toRemove -= Positions[j].Shares; } } } foreach (Position pos in positionsToRemove) { Positions.Remove(pos); } // fire event Strategy.ProcessOrder(this, Orders[i], realSellPrice); // log Log("Sold " + Orders[i].Shares + " shares of " + Orders[i].Symbol + " for $" + realSellPrice + " per share."); // remove this order Orders.Remove(Orders[i]); } } else if (Orders[i].OrderType == OrderType.Market) { // sell the shares! BuyingPower += history.Last().Open *Orders[i].Shares; int toRemove = Orders[i].Shares; List <Position> positionsToRemove = new List <Position>(); // remove the position for (int j = 0; j < Positions.Count; j++) { if (Positions[j].Symbol == Orders[i].Symbol) { if (Positions[j].BuyPrice >= history.Last().Open) { Losses++; } else { Wins++; } if (Positions[j].Shares > toRemove) { Positions[j].Shares -= toRemove; break; } else if (Positions[j].Shares == toRemove) { positionsToRemove.Add(Positions[j]); break; } else if (Positions[j].Shares < toRemove) { positionsToRemove.Add(Positions[j]); toRemove -= Positions[j].Shares; } } } foreach (Position pos in positionsToRemove) { Positions.Remove(pos); } // fire event Strategy.ProcessOrder(this, Orders[i], history.Last().Open); // log Log("Sold " + Orders[i].Shares + " shares of " + Orders[i].Symbol + " for $" + history.Last().Open + " per share."); // remove this order Orders.Remove(Orders[i]); } } } // now, what box orders were placed overnight? for (int i = 0; i < BoxOrders.Count; i++) { List <BarData> history = MarketState.FirstOrDefault(x => x.Key == BoxOrders[i].Symbol).Value; if (BoxOrders[i].ActionType == ActionType.Buy) { // todo: } else if (BoxOrders[i].ActionType == ActionType.Sell) { double realSellPrice = -1; // has the stocks price gone over or below either of the limit prices today? if (history.Last().High >= BoxOrders[i].UpperLimitPrice && history.Last().Low <= BoxOrders[i].UpperLimitPrice) { realSellPrice = BoxOrders[i].UpperLimitPrice; } else if (history.Last().High >= BoxOrders[i].LowerLimitPrice && history.Last().Low <= BoxOrders[i].LowerLimitPrice) { realSellPrice = BoxOrders[i].LowerLimitPrice; } else if (BoxOrders[i].UpperLimitPrice <history.Last().Open&& BoxOrders[i].UpperLimitPrice> history[history.Count - 2].High) { realSellPrice = history.Last().Open; } else if (BoxOrders[i].LowerLimitPrice <history.Last().Open&& BoxOrders[i].LowerLimitPrice> history[history.Count - 2].High) { realSellPrice = history.Last().Open; } else if (BoxOrders[i].UpperLimitPrice > history.Last().Open&& BoxOrders[i].UpperLimitPrice < history[history.Count - 2].Low) { realSellPrice = history.Last().Open; } else if (BoxOrders[i].LowerLimitPrice > history.Last().Open&& BoxOrders[i].LowerLimitPrice < history[history.Count - 2].Low) { realSellPrice = history.Last().Open; } if (realSellPrice != -1) { // sell the shares! BuyingPower += realSellPrice * BoxOrders[i].Shares; Equity += (realSellPrice - history.Last().Open) * BoxOrders[i].Shares; int toRemove = BoxOrders[i].Shares; List <Position> positionsToRemove = new List <Position>(); // remove the position for (int j = 0; j < Positions.Count; j++) { if (Positions[j].Symbol == BoxOrders[i].Symbol) { if (Positions[j].BuyPrice >= realSellPrice) { Losses++; } else { Wins++; } if (Positions[j].Shares > toRemove) { Positions[j].Shares -= toRemove; break; } else if (Positions[j].Shares == toRemove) { positionsToRemove.Add(Positions[j]); break; } else if (Positions[j].Shares < toRemove) { positionsToRemove.Add(Positions[j]); toRemove -= Positions[j].Shares; } } } foreach (Position pos in positionsToRemove) { Positions.Remove(pos); } // fire event Strategy.ProcessBoxOrder(this, BoxOrders[i], realSellPrice); // log Log("Sold " + BoxOrders[i].Shares + " shares of " + BoxOrders[i].Symbol + " for $" + realSellPrice + " per share."); // remove this order BoxOrders.Remove(BoxOrders[i]); } } } }