protected override void CalcBar() { double Rating = m_RSI[0]; // Get RSI function value for the current bar. if (!Environment.IsRealTimeCalc) // There is no need to calculate on historical data, that is why backtesting is ignored { // As soon as backtesting is finished, the signal gets immediately calculated by the timer. // It is necessary to calculate RSI function value, which can be requested by MM-signal at any moment. ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(5)); return; } StaretegyEvents cmd = StaretegyEvents.None; object obj = MyPortfolioData["MM_Command"]; // Check, if there are any MM-signal events available if (!object.Equals(obj, null)) { cmd = (StaretegyEvents)obj; } Output.WriteLine("\t\t{0}: Symbol: {1}, Command: {2}", DateTime.Now, Bars.Info.Name, cmd); switch (cmd) // Execute specific commands, depending on the event { case StaretegyEvents.GetFactor: // If MM-signal requested rating coefficient from the signal, it will be sent. MyPortfolioData["RankingValue"] = Rating; // In this case it is RSI function value on the current bar. MyPortfolioData["MM_Command"] = StaretegyEvents.DataWasSent; // And will inform that the data was sent. Output.WriteLine("\t\t{0}: Send Data for Symbol: {1}\t{2}", DateTime.Now, Bars.Info.Name, Rating); ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(5)); // Also, it is necessary to re-calculate, as the final instructions were not received yet. break; case StaretegyEvents.GenerateOrders_Long: // If MM-signal gives command to generate a long entry order buy_order.Send(); // the signal will execute it here. Output.WriteLine("\t\t{0}: Generate Buy. {1}", DateTime.Now, Bars.Info.Name); break; case StaretegyEvents.GenerateOrders_Short: // If MM-signal gives command to generate a short entry order sell_order.Send(); // the signal will execute it here. Output.WriteLine("\t\t{0}: Generate Short. {1}", DateTime.Now, Bars.Info.Name); break; case StaretegyEvents.None: ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(5)); // If there were no instructions from MM-signal, we will keep waiting for them. break; } if (Bars.Status == EBarState.Close) // During calculation at the bar close, global variables, used to exchange messages between the current signal and MM-signal { // should be zeroed MyPortfolioData["RankingValue"] = 0; MyPortfolioData["MM_Command"] = StaretegyEvents.None; Output.WriteLine("\t\tSeries {0} is Closed with Ranking Value: {1}. Status: {2}, cmd: {3}", Bars.Info.Name, Rating, Bars.Status, cmd); ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(5)); // And start the timer to wait for the new commands from MM-signal } }
protected override void CalcBar() { if (!Bars.LastBarOnChart) { return; // Ignore BackTesting } TimeSpan currentTime = DateTime.Now.TimeOfDay; // Get the current time int strategiesCount = PortfolioStrategies.Count; m_time = GetCloseTime() - TimeSpan.FromSeconds(30); // and calculate the moment when the calculated coefficient will be requested from each trading strategy. // In this case - 30 seconds before the bar close #region Request Data if (Bars.Status == EBarState.Close) // When the bar closes, it is necessary to clear the collection of coefficients { // it will be a flag: if the collection is empty, then either the calculation has just started, or RankFromStrategies.Clear(); // the new bar has appeared and we need to get new coefficients. return; // The request of new values of coefficients will be executed on the new bar already. } StaretegyEvents cmd = StaretegyEvents.None; if (currentTime >= m_time && RankFromStrategies.Count != strategiesCount) // If it is already necessary to request values from signals, we start the process of receiving values { for (int idx = 0; idx < strategiesCount; idx++) // We address to each signal in cycle: { PortfolioStrategies[idx].Status = ""; object obj = PortfolioStrategies[idx].PortfolioData["MM_Command"]; if (!object.Equals(obj, null)) { cmd = (StaretegyEvents)obj; } if (cmd != StaretegyEvents.DataWasSent) // if it did not yet send the data { PortfolioStrategies[idx].PortfolioData["MM_Command"] = StaretegyEvents.GetFactor; // we make a request Output.WriteLine("{0} MMS: Request Factor", DateTime.Now); } } RankFromStrategies.Clear(); // Clear the collection from the old values } #endregion var inLongStrategies = new List <int>(); var inShortStrategies = new List <int>(); #region Load Data if (RankFromStrategies.Count == 0) // The data should be received from all the strategies at the same time { for (int idx = 0; idx < strategiesCount; idx++) { StaretegyEvents _flag = StaretegyEvents.None; object _o = PortfolioStrategies[idx].PortfolioData["MM_Command"]; if (!object.Equals(_o, null)) { _flag = (StaretegyEvents)_o; } if (_flag != StaretegyEvents.DataWasSent) // if a strategy did not yet send its data { RankFromStrategies.Clear(); // we will initiate receiving data until it is done { return; // otherwise, the signal will not be able to correctly evaluate the market situation } } double rankingValue = 0; rankingValue = PortfolioStrategies[idx].PortfolioData["RankingValue"].safe_cast2double(); // The type of received values should be changed to double PortfolioStrategies[idx].Status = String.Format("{0:0.00}", rankingValue); // and output them into the table, to Custom Text column Output.WriteLine("{1} MMS: data received: {0}", PortfolioStrategies[idx].Signals[0].Bars.Info.Name, DateTime.Now); RankFromStrategies.Add(idx, rankingValue); // Put the received data into the collection PortfolioStrategies[idx].PortfolioData["MM_Command"] = StaretegyEvents.None; // Remove command for data request. It is not needed to execute it on the current bar. } RankFromStrategies = RankFromStrategies.OrderByDescending(elem => elem.Value).ToDictionary(x => x.Key, y => y.Value); // When values of all the coefficiens are received, sort out the collection in descending order // symbols with maximum coefficient value will be at the top // symbols with minimum values will be at the bottom } #endregion int inShortcnt = this.StrategiesInShort(ref inShortStrategies); // Get the number of opened short positions int inLongtcnt = this.StrategiesInLong(ref inLongStrategies); // Get the number of opened long positions TimeSpan dif = DateTime.Now - m_LastTraceTime; // Trace the intermediate values if (dif.Seconds > 1) { Output.WriteLine("{7} MMS: {0} CalcBar. Bar Time: {1}, reqtime: {2}, strategiesToEnter.Count: {3}, strategiesCount: {4}, inShortcnt: {5}, inLongtcnt: {6}", currentTime, Bars.TimeValue, m_time, RankFromStrategies.Count, strategiesCount, inShortcnt, inLongtcnt, DateTime.Now); m_LastTraceTime = DateTime.Now; } if (RankFromStrategies.Count == strategiesCount) // Make sure that all the coefficients were received and start sending commands to the signals { int CountNewPositionsBest = MaxBest - inShortcnt; // Calculate how many additional short orders can be generated int CountNewPositionsWorst = MaxWorst - inLongtcnt; // and long orders for (int idx = 0; idx < Math.Min(CountNewPositionsBest, strategiesCount); idx++) // and select the best symbols in the cycle and send the command to generate the order { if (idx >= RankFromStrategies.Count()) { break; } int key = RankFromStrategies.Keys.ElementAt(idx); double value = RankFromStrategies[key]; if (Environment.IsAutoTradingMode && Bars.LastBarOnChart) { Output.WriteLine(DateTime.Now.ToString() + " MMS: " + currentTime + "; idx: " + key + "; Symbol To Enter: " + PortfolioStrategies[key].Signals[0].Bars.Info.Name + "; Rank: " + value); } if (value > 65) // ...if the coefficient values allow to do that { PortfolioStrategies[key].PortfolioData["MM_Command"] = StaretegyEvents.GenerateOrders_Short; // command to send short entry order is given to the specified strategy } } for (int idx = strategiesCount - 1; idx > strategiesCount - Math.Min(CountNewPositionsWorst, strategiesCount) && idx > 0; idx--) // the same for the long position { // but coefficients are taken from the bottom of the list, that is, the worst if (idx >= RankFromStrategies.Count() || idx < 0) { break; } int key = RankFromStrategies.Keys.ElementAt(idx); double value = RankFromStrategies[key]; if (Environment.IsAutoTradingMode && Bars.LastBarOnChart) { Output.WriteLine(DateTime.Now.ToString() + " MMS: " + currentTime + "; idx: " + key + "; Symbol To Enter: " + PortfolioStrategies[key].Signals[0].Bars.Info.Name + "; Rank: " + value); } if (value < 35) { PortfolioStrategies[key].PortfolioData["MM_Command"] = StaretegyEvents.GenerateOrders_Long; } } } }