public HyperlinkCrawlerStrategy( HyperlinkCrawlerSettings settings, HttpClient httpClient, ILogger logger, HyperlinkCrawlRequest request) : base(httpClient, logger, request, settings.MaxUriProcessingDegreeOfParallelism) { _settings = settings; _httpClient = httpClient; _logger = logger; _crawlCompleteTokenLock = new SemaphoreSlim(1, 1); _events = new StrategyEvents( accepted => { _state.AddAccepted(accepted); _logger.LogDebug($"Accepted URI: {accepted.Uri}"); }, processed => { _state.AddProcessed(processed); _logger.LogDebug($"Processed URI: {processed.Uri}"); }, failure => { _state.AddFailure(failure); _logger.LogDebug($"Failed URI: {failure.Uri}"); }, discovered => { _state.AddDiscovered(discovered); _logger.LogDebug($"Discovered URIs: {discovered.Uris.Count}" + string.Join(Environment.NewLine, discovered.Uris)); }); }
protected override void CalcBar() { CurSpecOrdersMode = ESpecOrdersMode.PerPosition; 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 the CRTDR and other values which can be requested by MM-signal at any moment. ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(recalcFrequency)); return; } // This method will be called over and over again because of the RecalcLastBarAfter setting // Since we do not want to get the same logs all the time we have a throttling in place // which will allow only certain calls to really log their output. // Depending on the time of the day we log more of less often. UpdateLogThrottling(); var high = Bars.HighValue; var low = Bars.LowValue; var close = Bars.CloseValue; var crtdr = CRTDRIndicatorMath.CalcNextValue(high, low, close); var xAverageLongValue = xAverageLong.Value; var xAverageShortValue = xAverageShort.Value; var trend = GetTrend(close, xAverageLongValue, xAverageShortValue); var rsiDown = cutlersRSIIndicatorMathDown.Value; var rsiFlat = cutlersRSIIndicatorMathFlat.Value; var rsiUp = cutlersRSIIndicatorMathUp.Value; var rsi = trend == Trend.Down ? rsiDown : (trend == Trend.Up ? rsiUp : rsiFlat); MyPortfolioData[PortfolioDataKeys.IWantToBuy] = false; MyPortfolioData[PortfolioDataKeys.IWantToSell] = false; MyPortfolioData[PortfolioDataKeys.CRTDR] = crtdr; LogThrottled("Reason: {0}, Status: {1}, Open: {2}, High: {3}, Low: {4}, Close: {5}, RSI: {6}, CRTDR: {7}, xAvgLong: {8}, xAvgShort: {9}", Environment.CalcReason, Bars.Status, Bars.OpenValue, Bars.HighValue, Bars.LowValue, Bars.CloseValue, rsi, crtdr, xAverageLongValue, xAverageShortValue); if (StrategyInfo.MarketPosition == 0) { if (GetSignalUp(crtdr, rsi, trend)) { //var numLots = Convert.ToInt32((InitialCapital + (doReinvestment ? Portfolio.NetProfit : 0.0)) / Bars.CloseValue); MyPortfolioData[PortfolioDataKeys.IWantToBuy] = true; LogThrottled("Signal says: We would like to buy @ {0}$", Bars.CloseValue); } // else if (GetSignalDown(crtdr, rsi, trend)) // { // Output.WriteLine("SHORT on {0}, high {1} low {2} close {3} rsi {4} crtdr {5} xAverageLong {6} xAverageShort {7}", Bars.TimeValue, high, low, close, rsi, crtdr, xAverageLongValue, xAverageShortValue); // MyPortfolioData[PortfolioHelpFunctions.PotentialEntryPrice] = -Bars.CloseValue; // sellShortOrder.Send(Convert.ToInt32((InitialCapital + (doReinvestment ? Portfolio.NetProfit : 0.0)) / 10.0 / Bars.CloseValue)); // } // else // { // Log("--- FLAT - NOP ---"); // } } else if (StrategyInfo.MarketPosition > 0) { // WE ARE LONG //var barsSinceEntry = Bars.CurrentBar - CurrentPosition.OpenTrades[0].EntryOrder.BarNumber; // BarsSinceEntry() doesn't work upon the restart of a trading session in which case BarsSinceEntry() will be zero no matter when the deals were actually opened var barsSinceEntry = Math.Min(1, this.BarsSinceEntry()); var openProfit = CurrentPosition.OpenProfit; var signalUp = GetSignalUp(crtdr, rsi, trend); var rsiSellLevel = GetRsiSellLevel(trend); LogThrottled("Should we sell? Bars since entry: {0}, open profit: {1}, signal up: {2}, rsi: {3}, rsiSellLevel: {4}", barsSinceEntry, openProfit, signalUp, rsi, rsiSellLevel); // close non-profitable positions straight away because we have picked a loser and need to free up money for new deals if (openProfit < 0) { LogThrottled("Loser cut! Assumed loss: {0}$", CurrentPosition.OpenProfit); MyPortfolioData[PortfolioDataKeys.IWantToSell] = true; } else if (barsSinceEntry > 2 && !signalUp) { LogThrottled("SELL! Bars since entry > 2 and no up signal. Assuming to cash in ~{0}$", CurrentPosition.OpenProfit); MyPortfolioData[PortfolioDataKeys.IWantToSell] = true; } else if (rsi > rsiSellLevel) { LogThrottled("SELL! RSI condition satisfied, we take the profit (~{0}$) and run!", CurrentPosition.OpenProfit); MyPortfolioData[PortfolioDataKeys.IWantToSell] = true; } else { //Log("--- LONG - NOP ---"); } } // else if(marketPosition < 0) // { // // WE ARE SHORT // GenerateStopLoss(StrategyInfo.AvgEntryPrice * Math.Abs(marketPosition) * StopLossLevel); // // if(this.BarsSinceEntry() > 2 && !GetSignalDown(crtdr, rsi, trend)) // { // //Output.WriteLine("{8}: COVER1 on {0}, high {1} low {2} close {3} rsi {4} crtdr {5} xAverageLong {6} xAverageShort {7}", Bars.TimeValue, high, low, close, rsi, crtdr, xAverageLongValue, xAverageShortValue, Bars.Info.Name); // buyToCoverOrder.Send(); // } // else if(rsi < (trend == Trend.Down ? RsiCoverLevelDown : (trend == Trend.Up ? RsiCoverLevelUp : RsiCoverLevelFlat))) // { // //Output.WriteLine("{8}: COVER2 on {0}, high {1} low {2} close {3} rsi {4} crtdr {5} xAverageLong {6} xAverageShort {7}", Bars.TimeValue, high, low, close, rsi, crtdr, xAverageLongValue, xAverageShortValue, Bars.Info.Name); // buyToCoverOrder.Send(); // } // else // { // Log("--- SHORT - NOP ---"); // } // } StrategyEvents cmd = StrategyEvents.None; object obj = MyPortfolioData[PortfolioDataKeys.MoneyManagementCommand]; // Check, if there are any MM-signal events available if (obj != null) { cmd = (StrategyEvents)obj; } //Log("Got command {0}", cmd); switch (cmd) // Execute specific commands, depending on the event { case StrategyEvents.GenerateOrders_Long: int numberOfShares = Convert.ToInt32(MyPortfolioData[PortfolioDataKeys.NumberOfShares]); buyOrder.Send(numberOfShares); LogThrottled("Generated Buy: {0}#", numberOfShares); GenerateOrAdjustStopLosses(); break; case StrategyEvents.GenerateOrders_Short: sellOrder.Send(); LogThrottled("Generated Sell."); break; case StrategyEvents.None: ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(recalcFrequency)); break; } // During calculation at the bar close, global variables, used to exchange messages between the current signal and MM-signal should be reset if (Bars.Status == EBarState.Close) { Log("Close event received."); // only send email output if trade has been sent on this day DumpFileLog(); MyPortfolioData[PortfolioDataKeys.CRTDR] = 1.0; MyPortfolioData[PortfolioDataKeys.MoneyManagementCommand] = StrategyEvents.None; MyPortfolioData[PortfolioDataKeys.IWantToBuy] = false; MyPortfolioData[PortfolioDataKeys.IWantToSell] = false; MyPortfolioData[PortfolioDataKeys.NumberOfShares] = 0; ExecControl.RecalcLastBarAfter(TimeSpan.FromSeconds(recalcFrequency)); // And start the timer to wait for the new commands from MM-signal } }