/// <summary> /// Called for every bar update. Find instrument (ticker) with the highest /// win percent and buy that stock if we have enough money. /// </summary> /// <param name="currentDate">The date that the sim is on.</param> /// <param name="barNumber">The bar number of the sim loop. Not to be used for indexing since each ticker has a different number of bars</param> private void OnBarUpdate(DateTime currentDate, int barNumber) { bool isTradingBar = false; ConcurrentBag<BestOfRootStrategies> buyBag = new ConcurrentBag<BestOfRootStrategies>(); // Add all the tickers that are above our set percent to buy. #if DEBUG foreach (KeyValuePair<string, BestOfRootStrategies> instrument in Instruments) #else Parallel.ForEach(Instruments, instrument => #endif { BestOfRootStrategies strat = instrument.Value; int currentBar = strat.Data.GetBar(currentDate); if (currentBar != -1) { isTradingBar = true; // Run the strategy for this bar. strat.OnBarUpdate(currentBar); // All bars have a zero value by default. So something is found when the // percent is higher than that. if (strat.Bars[currentBar].HighestPercent > 0.0) { // All orders set a min price to place an order. if (strat.Data.Open[currentBar] >= Config.MinPriceForOrder) { // If this is a short order, some brokers have min prices they allow for shorts. if (strat.Bars[currentBar].StrategyOrderType == Order.OrderType.Long || (strat.Bars[currentBar].StrategyOrderType == Order.OrderType.Short && strat.Data.Open[currentBar] >= Config.MinPriceForShort)) { buyBag.Add(strat); } } } } #if DEBUG } #else }); #endif if (isTradingBar == true) { List<BestOfRootStrategies> buyList = buyBag.ToList(); // Sort the list so the instruments that have the highest buy value are first in the list. buyList.Sort(delegate(BestOfRootStrategies x, BestOfRootStrategies y) { int xBar = x.Data.GetBar(currentDate); int yBar = y.Data.GetBar(currentDate); if (x.Bars[xBar].ExtraOrderInfo.ContainsKey("expectedGain")) { double xGain = (double)x.Bars[xBar].ExtraOrderInfo["expectedGain"]; double yGain = (double)y.Bars[yBar].ExtraOrderInfo["expectedGain"]; return yGain.CompareTo(xGain); } else { return y.Bars[yBar].HighestGain.CompareTo(x.Bars[xBar].HighestGain); } }); // Output the buy list for each day. DataOutput.SaveBuyList(buyList, currentDate); // Update all the active orders before placing new ones. UpdateOrders(currentDate); // Keep tabs on the account cash at the start of the month. We want to // limit our losses for the month. UpdateMonthlyAccountValue(currentDate); // Buy stocks if it's a good time. if (barNumber >= Config.NumBarsToDelayStart) { int currentCount = 0; for (int i = 0; i < buyList.Count; i++) { // Only allowed to have a maximum number of orders open at 1 time. This will limit us // to working within a budget later in the sim when we make money. Ex. If we start with // $100,000 and we double it in 2 years. We don't want to be investing our $200,000 worth // of cash. We still want to work with our original amount. This way we can see how much // of a bankroll we'll need to make a living off investing. if (_activeOrders.Count >= Config.MaxOpenOrders || currentCount >= Config.MaxOrdersPerBar) { break; } // Also limit our losses and make sure we have not lost too much money this month. if (_isMonthlyLossExceeded) { break; } // If the highest percent is enough for a buy, then do it. // If not then since the list is sorted, no other ones will // be high enough and we can early out of the loop. int strategyBarIndex = buyList[i].Data.GetBar(currentDate); OrderSuggestion barStats = buyList[i].Bars[strategyBarIndex]; if (barStats.HighestPercent > 0) // TODO: move to combo strategy && barStats.ComboSizeOfHighestStrategy >= Simulator.Config.MinComboSizeToBuy) { // Make sure we have enough money and also that we have enough time // before the end of the sim to complete the order we place. if (barNumber < NumberOfBars && Broker.AccountCash > barStats.SizeOfOrder * 1.1) { double sizeOfOrder = GetOrderSize(strategyBarIndex, barStats.SizeOfOrder, barStats.StrategyOrderType, buyList[i].Data); currentCount += EnterOrder(barStats.Statistics, barStats.StrategyOrderType, buyList[i].Data, strategyBarIndex, sizeOfOrder, barStats.DependentIndicators, barStats.BuyConditions, barStats.SellConditions, barStats.ExtraOrderInfo); } } else { break; } } } } }