private void SetVolts(double volt, int voltIndex) { if (!IsRatesLengthStable) { return; } if (double.IsInfinity(volt) || double.IsNaN(volt)) { return; } UseRates(rates => rates.BackwardsIterator().TakeWhile(r => GetVoltByIndex(voltIndex)(r).IsNaN()) .ForEach(r => SetVoltByIndex(voltIndex)(r, volt))); //SetVoltage(RateLast, volt); var voltRates = RatesArray.Select(GetVoltByIndex(voltIndex)).SkipWhile(v => v.IsNaN()) .Scan((p, n) => n.IsNaN() ? p : n) .ToArray(); if (voltRates.Any()) { GeneralPurposeSubject.OnNext(() => { try { var voltageAvgLow = voltRates.AverageByIterations(-VoltAverageIterationsByIndex(voltIndex)).DefaultIfEmpty(double.NaN).Average(); SetVoltLowByIndex(voltIndex)(voltageAvgLow); var voltageAvgHigh = voltRates.AverageByIterations(VoltAverageIterationsByIndex(voltIndex)).DefaultIfEmpty(double.NaN).Average(); SetVoltHighByIndex(voltIndex)(voltageAvgHigh); } catch (Exception exc) { Log = exc; } }); } }
// SetVoltHighByIndex(voltIndex)(min.Abs()); // SetVoltLowByIndex(voltIndex)(-min.Abs()); private void SetVolts(double volt, Func <Rate, double> getVolt, Action <Rate, double> setVolt, double cma = 0) { if (!IsRatesLengthStable) { return; } if (double.IsInfinity(volt) || double.IsNaN(volt)) { return; } var volt2 = cma > 0 ? GetLastVolt(getVolt).Select(v => v.Cma(cma, volt)).DefaultIfEmpty(volt).SingleOrDefault() : volt; UseRates(rates => rates.Where(r => getVolt(r).IsNaN()).ToList()) .SelectMany(rates => rates).ForEach(r => setVolt(r, volt2)); //SetVoltage(RateLast, volt); if (getVolt != GetVoltage) { return; } var voltRates = RatesArray.Select(getVolt).SkipWhile(v => v.IsNaN()).ToArray(); if (voltRates.Any()) { GeneralPurposeSubject.OnNext(() => { try { var voltageAvgLow = voltRates.AverageByIterations(-VoltAverageIterations).DefaultIfEmpty(double.NaN).Average(); GetVoltageAverage = () => new[] { voltageAvgLow }; var voltageAvgHigh = voltRates.AverageByIterations(VoltAverageIterations).DefaultIfEmpty(double.NaN).Average(); GetVoltageHigh = () => new[] { voltageAvgHigh }; } catch (Exception exc) { Log = exc; } }); } }
private CorridorStatistics ScanCorridorByFft(IList <Rate> ratesForCorridor, Func <Rate, double> priceHigh, Func <Rate, double> priceLow) { var ratesReversed = ratesForCorridor.ReverseIfNot().ToArray(); var FftReversed = false; FftMax = ratesReversed.Select(_priceAvg).FftFrequency(FftReversed).ToInt(); var startMax = CorridorStopDate.IfMin(DateTime.MaxValue); var startMin = CorridorStartDate.GetValueOrDefault(ratesReversed[CorridorDistanceRatio.ToInt() - 1].StartDate); Lazy <int> lenghForwardOnly = new Lazy <int>(() => { var date = CorridorStats.Rates.LastOrDefault()?.StartDate; return(ratesReversed.TakeWhile(r => r.StartDate >= date).Count()); }); var lengthMax = !IsCorridorForwardOnly || CorridorStats.StartDate.IsMin() ? int.MaxValue : lenghForwardOnly.Value; WaveShort.Rates = null; WaveShort.Rates = startMax.IsMax() && !CorridorStartDate.HasValue ? ratesReversed.Take(FftMax.Min(lengthMax)).ToArray() : ratesReversed.SkipWhile(r => r.StartDate > startMax).TakeWhile(r => r.StartDate >= startMin).ToArray(); var corridor = WaveShort.Rates.ScanCorridorWithAngle(CorridorGetHighPrice(), CorridorGetLowPrice(), TimeSpan.Zero, PointSize, CorridorCalcMethod); SetVoltage(ratesReversed[0], WaveShort.Rates.Select(_priceAvg).FftFrequency(FftReversed) / (double)WaveShort.Rates.Count); var volts = RatesArray.Select(r => GetVoltage(r)).SkipWhile(v => v.IsNaN()).ToArray(); double voltsAvg; var voltsStdev = volts.StDev(out voltsAvg); GetVoltageAverage = () => new[] { voltsAvg }; GetVoltageHigh = () => new[] { voltsAvg + voltsStdev }; return(corridor); }
private void StrategyEnterUniversal() { if (!RatesArray.Any() || !IsTrader) { return; } #region ============ Local globals ============ #region Loss/Gross Func <double> currentGrossInPips = () => CurrentGrossInPipTotal; Func <double> currentLoss = () => CurrentLoss; Func <double> currentGross = () => CurrentGross; Func <bool> isCurrentGrossOk = () => CurrentGrossInPips >= -SpreadForCorridorInPips; #endregion var reverseStrategy = new ObservableValue <bool>(false); Func <SuppRes, bool> isBuyR = sr => reverseStrategy.Value ? !sr.IsBuy : sr.IsBuy; Func <SuppRes, bool> isSellR = sr => reverseStrategy.Value ? !sr.IsSell : sr.IsSell; Action resetCloseAndTrim = () => CloseAtZero = false; Func <bool, double> enter = isBuy => CalculateLastPrice(RateLast, GetTradeEnterBy(isBuy)); #endregion #region ============ Init ================= bool _useSms = false; if (_strategyExecuteOnTradeClose == null) { Func <SuppRes, IObservable <EventPattern <EventArgs> > > onCanTrade = sr => Observable.FromEventPattern <EventHandler <EventArgs>, EventArgs>(h => h, h => sr.CanTradeChanged += h, h => sr.CanTradeChanged -= h); if (IsInVirtualTrading && Trades.Any()) { throw new Exception("StrategyEnterUniversal: All trades must be closed befor strategy init."); } if (IsInVirtualTrading) { TurnOffSuppRes(RatesArray.Select(r => r.PriceAvg).DefaultIfEmpty().Average()); } Func <bool, Func <Rate, double> > tradeExit = isBuy => MustExitOnReverse ? _priceAvg : GetTradeExitBy(isBuy); Action onEOW = () => { }; #region Exit Funcs #region exitOnFriday Func <bool> exitOnFriday = () => { if (!SuppRes.Any(sr => sr.InManual)) { bool isEOW = IsAutoStrategy && IsEndOfWeek(); if (isEOW) { if (Trades.Any()) { CloseTrades(Trades.Lots(), "exitOnFriday"); } BuyLevel.CanTrade = SellLevel.CanTrade = false; return(true); } } return(false); }; Func <bool?> exitOnCorridorTouch = () => { var mustSell = false; var mustBuy = false; var currentBuy = CalculateLastPrice(_priceAvg); var currentSell = currentBuy; if (currentBuy >= RateLast.PriceAvg2) { mustSell = true; } if (currentSell <= RateLast.PriceAvg3) { mustBuy = true; } if (Trades.HaveBuy() && mustSell || Trades.HaveSell() && mustBuy) { MustExitOnReverse = true; } return(mustBuy ? mustBuy : mustSell?false : (bool?)null); }; #endregion #region exitByLimit Action exitByLimit = () => { if (!exitOnFriday() && CurrentGross > 0 && TradesManager.MoneyAndLotToPips(OpenTradesGross, Trades.Lots(), Pair) >= CalculateTakeProfitInPips() * ProfitToLossExitRatio) { CloseAtZero = true; } }; #endregion //TradesManager.MoneyAndLotToPips(-currentGross(), LotSizeByLossBuy, Pair) #region exitVoid Action exitVoid = () => { }; #endregion #region exitFunc Func <Action> exitFunc = () => { if (!Trades.Any()) { return () => { } } ; switch (ExitFunction) { case Store.ExitFunctions.Void: return(exitVoid); case Store.ExitFunctions.Friday: return(() => exitOnFriday()); case Store.ExitFunctions.Limit: return(exitByLimit); case Store.ExitFunctions.CorrTouch: return(() => exitOnCorridorTouch()); } throw new NotSupportedException(ExitFunction + " exit function is not supported."); }; #endregion #endregion #region TurnOff Funcs Action <double, Action> turnOffIfCorridorInMiddle_ = (sections, a) => { var segment = RatesHeight / sections; var rest = (RatesHeight - segment) / 2; var bottom = _RatesMin + rest; var top = _RatesMax - rest; var tradeLevel = (BuyLevel.Rate + SellLevel.Rate) / 2; if ((BuyLevel.CanTrade || SellLevel.CanTrade) && IsAutoStrategy && tradeLevel.Between(bottom, top)) { a(); } }; Action <Action> turnOffByCrossCount = a => { if (BuyLevel.TradesCount.Min(SellLevel.TradesCount) < TradeCountMax) { a(); } }; Action <Action> turnOffByWaveHeight = a => { if (WaveShort.RatesHeight < RatesHeight * .75) { a(); } }; Action <Action> turnOffByWaveShortLeft = a => { if (WaveShort.Rates.Count < WaveShortLeft.Rates.Count) { a(); } }; Action <Action> turnOffByWaveShortAndLeft = a => { if (WaveShortLeft.Rates.Count < CorridorDistanceRatio && WaveShort.Rates.Count < WaveShortLeft.Rates.Count) { a(); } }; Action <Action> turnOff = a => { switch (TurnOffFunction) { case Store.TurnOffFunctions.Void: return; case Store.TurnOffFunctions.WaveHeight: turnOffByWaveHeight(a); return; case Store.TurnOffFunctions.WaveShortLeft: turnOffByWaveShortLeft(a); return; case Store.TurnOffFunctions.WaveShortAndLeft: turnOffByWaveShortAndLeft(a); return; case Store.TurnOffFunctions.InMiddle_4: turnOffIfCorridorInMiddle_(4, a); return; case Store.TurnOffFunctions.InMiddle_5: turnOffIfCorridorInMiddle_(5, a); return; case Store.TurnOffFunctions.InMiddle_6: turnOffIfCorridorInMiddle_(6, a); return; case Store.TurnOffFunctions.InMiddle_7: turnOffIfCorridorInMiddle_(7, a); return; case Store.TurnOffFunctions.CrossCount: turnOffByCrossCount(a); return; } throw new NotSupportedException(TurnOffFunction + " Turnoff function is not supported."); }; #endregion if (_adjustEnterLevels != null) { _adjustEnterLevels.GetInvocationList().Cast <Action>().ForEach(d => _adjustEnterLevels -= d); } if (BuyLevel != null) { BuyLevel.Crossed -= null; } if (SellLevel != null) { SellLevel.Crossed -= null; } Action <Trade> onCloseTradeLocal = null; Action <Trade> onOpenTradeLocal = null; #region Levels if (SuppResLevelsCount < 2) { SuppResLevelsCount = 2; } if (SuppRes.Do(sr => sr.IsExitOnly = false).Count() == 0) { return; } ; if (!IsInVirtualTrading) { var buySellCanTradeObservable = onCanTrade(BuyLevel).Merge(onCanTrade(SellLevel)) .Select(e => e.Sender as SuppRes) .DistinctUntilChanged(sr => sr.CanTrade) .Where(sr => _useSms && sr.CanTrade) .Subscribe(sr => SendSms(Pair + "::", new { sr.CanTrade }, false)); } if (BuyLevel.Rate.Min(SellLevel.Rate) == 0) { BuyLevel.RateEx = SellLevel.RateEx = RatesArray.Middle(); } BuyLevel.CanTrade = SellLevel.CanTrade = false; var _buySellLevels = new[] { BuyLevel, SellLevel }.ToList(); Action <Action> onCorridorCrossesMaximumExeeded = a => _buySellLevels.Where(bs => - bs.TradesCount >= TradeCountMax).Take(1).ForEach(_ => a()); ObservableValue <double> ghostLevelOffset = new ObservableValue <double>(0); Action <Action <SuppRes> > _buySellLevelsForEach = a => _buySellLevels.ForEach(sr => a(sr)); Action <Func <SuppRes, bool>, Action <SuppRes> > _buySellLevelsForEachWhere = (where, a) => _buySellLevels.Where(where).ToList().ForEach(sr => a(sr)); _buySellLevelsForEach(sr => sr.ResetPricePosition()); Action <SuppRes, bool> setCloseLevel = (sr, overWrite) => { if (!overWrite && sr.InManual) { return; } sr.InManual = false; sr.CanTrade = false; if (sr.TradesCount != 9) { sr.TradesCount = 9; } }; Func <SuppRes, SuppRes> suppResNearest = supRes => _suppResesForBulk().Where(sr => sr.IsSupport != supRes.IsSupport).OrderBy(sr => (sr.Rate - supRes.Rate).Abs()).First(); Action <bool> setCloseLevels = (overWrite) => setCloseLevel(BuyCloseLevel, overWrite); setCloseLevels += (overWrite) => setCloseLevel(SellCloseLevel, overWrite); ForEachSuppRes(sr => { if (IsInVirtualTrading) { sr.InManual = false; } sr.ResetPricePosition(); sr.ClearCrossedHandlers(); }); setCloseLevels(true); #region updateTradeCount Action <SuppRes, SuppRes> updateTradeCount = (supRes, other) => { if (supRes.TradesCount <= other.TradesCount && new[] { supRes, other }.Any(sr => sr.CanTrade)) { other.TradesCount = supRes.TradesCount - 1; } }; Func <SuppRes, SuppRes> updateNeares = supRes => { var other = suppResNearest(supRes); updateTradeCount(supRes, other); return(other); }; #endregion Func <bool, bool> onCanTradeLocal = canTrade => canTrade; Func <SuppRes, bool> canTradeLocal = sr => { var ratio = CanTradeLocalRatio; var corr = BuyLevel.Rate.Abs(SellLevel.Rate); var tradeDist = (sr.IsBuy ? (CurrentPrice.Ask - BuyLevel.Rate) : (SellLevel.Rate - CurrentPrice.Bid)); var tradeRange = ((sr.IsBuy ? (CurrentPrice.Ask - SellLevel.Rate) : (BuyLevel.Rate - CurrentPrice.Bid))) / corr; var canTrade = IsPrimaryMacro && (tradeRange < ratio || tradeDist <= PriceSpreadAverage); //if (!canTrade) //Log = new Exception(canTrade + ""); return(onCanTradeLocal(canTrade)); }; Func <bool> isTradingHourLocal = () => IsTradingHour() && IsTradingDay(); Func <bool> isLastRateHeightOk = () => RateLast.Yield().All(rl => (rl.AskHigh - rl.BidLow) / RatesHeight < 0.05); Func <SuppRes, bool> suppResCanTrade = (sr) => !CanDoEntryOrders && IsTradingActive && isTradingHourLocal() && sr.CanTrade && sr.TradesCount <= 0 && canTradeLocal(sr) && IsPriceSpreadOk && !IsEndOfWeek(); Func <bool> isProfitOk = () => Trades.HaveBuy() && RateLast.BidHigh > BuyCloseLevel.Rate || Trades.HaveSell() && RateLast.AskLow < SellCloseLevel.Rate; #endregion #region SuppRes Event Handlers Func <bool> isCrossActive = () => _buySellLevels.Any(sr => !sr.CanTrade) || BuyLevel.Rate.Abs(SellLevel.Rate) > InPoints(1); Func <SuppRes, bool> isCrossDisabled = sr => //!isCrossActive() || !IsTradingActive || !IsPrimaryMacro || (!sr.IsExitOnly && !sr.InManual && !CanOpenTradeByDirection(sr.IsBuy)); Action <double> onTradesCount = tc => { }; if (_strategyTradesCountHandler == null) { _strategyTradesCountHandler = BuyLevel.WhenAnyValue(x => x.TradesCount).Merge(SellLevel.WhenAnyValue(x => x.TradesCount)) .Throttle(TimeSpan.FromSeconds(.5)) .Subscribe(tc => onTradesCount(tc)); } #region enterCrossHandler Func <SuppRes, bool> enterCrossHandler = (suppRes) => { if (CanDoEntryOrders || CanDoNetStopOrders || (reverseStrategy.Value && !suppRes.CanTrade) || isCrossDisabled(suppRes) || HaveTrades(suppRes.IsBuy) || isHedgeChild || IsHedgedTrading) { return(false); } if (suppRes.InManual || BuyLevel.Rate > SellLevel.Rate || suppRes.CanTrade) { var isBuy = isBuyR(suppRes); var lot = Trades.IsBuy(!isBuy).Lots(); var canTrade = suppResCanTrade(suppRes); if (canTrade) { lot += AllowedLotSizeCore(isBuy); suppRes.TradeDate = ServerTime; } //var ghost = SuppRes.SingleOrDefault(sr => sr.IsExitOnly && sr.IsBuy == isBuy && sr.InManual && sr.CanTrade && sr.TradesCount <= 0); //if (ghost != null) { // var real = _buySellLevels.Single(sr => sr.IsBuy == isBuy); // if (real.IsBuy && real.Rate < ghost.Rate || real.IsSell && real.Rate > ghost.Rate) // real.Rate = ghost.Rate; //} OpenTrade(isBuy, lot, "enterCrossHandler:" + new { isBuy, suppRes.IsExitOnly }); return(canTrade); } else { return(false); } }; #endregion #region exitCrossHandler Action <SuppRes> exitCrossHandler = (sr) => { if ((!IsInVirtualTrading && CanDoNetLimitOrders) || isCrossDisabled(sr) || IsHedgedTrading || isHedgeChild || HaveHedgedTrades()) { return; } var lot = Trades.Lots(); resetCloseAndTrim(); if (TradingStatistics.TradingMacros.Distinct(tm => tm.Pair).Count() > 1 && ( CurrentGrossInPipTotal > PriceSpreadAverageInPips || CurrentGrossInPipTotal >= _tradingStatistics.GrossToExitInPips) ) { CloseTrading(new { exitCrossHandler = "", CurrentGrossInPipTotal, _tradingStatistics.GrossToExitInPips } +""); } else { CloseTrades(lot, "exitCrossHandler:" + new { sr.IsBuy, sr.IsExitOnly, CloseAtZero }); } }; #endregion #endregion #region Crossed Events #region Enter Levels #region crossedEnter EventHandler <SuppRes.CrossedEvetArgs> crossedEnter = (s, e) => { var sr = (SuppRes)s; if (sr.IsBuy && e.Direction == -1 || sr.IsSell && e.Direction == 1) { return; } var srNearest = new Lazy <SuppRes>(() => suppResNearest(sr)); updateTradeCount(sr, srNearest.Value); if (enterCrossHandler(sr)) { setCloseLevels(true); } }; #endregion BuyLevel.Crossed += crossedEnter; SellLevel.Crossed += crossedEnter; #endregion #region ExitLevels Action <SuppRes> handleActiveExitLevel = (srExit) => { updateNeares(srExit); if (enterCrossHandler(srExit)) { setCloseLevels(true); } }; EventHandler <SuppRes.CrossedEvetArgs> crossedExit = (s, e) => { var sr = (SuppRes)s; //if (reverseStrategy.Value && Trades.Any(t => t.IsBuy != sr.IsSell)) { // exitCrossHandler(sr); // return; //} if (sr.IsBuy && e.Direction == -1 || sr.IsSell && e.Direction == 1) { return; } if (sr.CanTrade) { if (sr.InManual) { handleActiveExitLevel(sr); } else { crossedEnter(s, e); } } else if (Trades.Any(t => t.IsBuy == sr.IsSell)) { exitCrossHandler(sr); } }; BuyCloseLevel.Crossed += crossedExit; SellCloseLevel.Crossed += crossedExit; #endregion #endregion #region adjustExitLevels Action <double, double> adjustExitLevels = AdjustCloseLevels(); Action adjustExitLevels0 = () => adjustExitLevels(double.NaN, double.NaN); Action adjustExitLevels1 = () => { if (DoAdjustExitLevelByTradeTime) { AdjustExitLevelsByTradeTime(adjustExitLevels); } else { adjustExitLevels(BuyLevel.Rate, SellLevel.Rate); } }; Action adjustExitLevels2 = () => { if (DoAdjustExitLevelByTradeTime) { AdjustExitLevelsByTradeTime(adjustExitLevels); } else { adjustExitLevels0(); } }; #endregion #region adjustLevels var firstTime = true; #region Watchers var watcherCanTrade = new ObservableValue <bool>(true, true); var corridorMovedTrigger = new ValueTrigger <ValueTrigger <bool> >(false) { Value = new ValueTrigger <bool>(false) }; var dateTrigger = new ValueTrigger <DateTime>(false); object[] bag = null; #region Workflow tuple factories Func <List <object> > emptyWFContext = () => new List <object>(); Func <List <object>, Tuple <int, List <object> > > tupleNext = e => Tuple.Create(1, e ?? new List <object>()); Func <object, Tuple <int, List <object> > > tupleNextSingle = e => tupleNext(new List <object> { e }); Func <Tuple <int, List <object> > > tupleNextEmpty = () => tupleNext(emptyWFContext()); Func <List <object>, Tuple <int, List <object> > > tupleStay = e => Tuple.Create(0, e ?? new List <object>()); Func <object, Tuple <int, List <object> > > tupleStaySingle = e => tupleStay(new[] { e }.ToList()); Func <Tuple <int, List <object> > > tupleStayEmpty = () => tupleStay(emptyWFContext()); Func <List <object>, Tuple <int, List <object> > > tuplePrev = e => Tuple.Create(-1, e ?? new List <object>()); Func <List <object>, Tuple <int, List <object> > > tupleCancel = e => Tuple.Create(int.MaxValue / 2, e ?? new List <object>()); Func <Tuple <int, List <object> > > tupleCancelEmpty = () => tupleCancel(emptyWFContext()); Func <IList <object>, Dictionary <string, object> > getWFDict = l => l.OfType <Dictionary <string, object> >().SingleOrDefault(); Func <IList <object>, Dictionary <string, object> > addWFDict = l => { var d = new Dictionary <string, object>(); l.Add(d); return(d); }; Func <IList <object>, Dictionary <string, object> > getAddWFDict = l => getWFDict(l) ?? addWFDict(l); #endregion Func <bool> cancelWorkflow = () => CloseAtZero; var workflowSubject = new Subject <IList <Func <List <object>, Tuple <int, List <object> > > > >(); var workFlowObservable = workflowSubject .Scan(new { i = 0, o = emptyWFContext(), c = cancelWorkflow }, (i, wf) => { if (i.i >= wf.Count || i.c() || i.o.OfType <WF.MustExit>().Any(me => me())) { i.o.OfType <WF.OnExit>().ForEach(a => a()); i.o.Clear(); i = new { i = 0, o = i.o, i.c }; } var o = wf[i.i](i.o);// Side effect o.Item2.OfType <WF.OnLoop>().ToList().ForEach(ol => ol(o.Item2)); try { return(new { i = (i.i + o.Item1).Max(0), o = o.Item2, i.c }); } finally { if (o.Item1 != 0) { workflowSubject.Repeat(1); } } }); var workflowSubjectDynamic = new Subject <IList <Func <ExpandoObject, Tuple <int, ExpandoObject> > > >(); var workFlowObservableDynamic = workflowSubjectDynamic.WFFactory(cancelWorkflow); #endregion #region Funcs Func <Func <Rate, double>, double> getRateLast = (f) => f(RateLast) > 0 ? f(RateLast) : f(RatePrev); Func <bool> runOnce = null; #endregion #region adjustEnterLevels Func <Trade, bool> minPLOk = t => IsAutoStrategy && false ? CurrentGrossInPips == 0 : t.NetPL2 > 0; Action <Action> firstTimeAction = a => { if (firstTime) { Log = new Exception(new { CorrelationMinimum, CorridorDistance } +""); workFlowObservableDynamic.Subscribe(); #region onCloseTradeLocal onCanTradeLocal = canTrade => canTrade || Trades.Any(); onCloseTradeLocal += t => { var tpByGross = InPoints(_tradingStatistics.GetNetInPips()).Min(0).Abs() / 3; TakeProfitManual = (t.PL < 0 ? InPoints(t.PL.Abs() * 1.4).Max(TakeProfitManual) : double.NaN).Max(tpByGross); TakeProfitManual = double.NaN; BroadcastCloseAllTrades(this, tm => OnCloseTradeLocal(new[] { t }, tm)); }; #endregion if (a != null) { a(); } } }; Action adjustEnterLevels = () => { if (firstTime) { onOpenTradeLocal += t => { }; } switch (TrailingDistanceFunction) { #region SimpleMove case TrailingWaveMethod.SimpleMove: { var conditions = MonoidsCore.ToFunc(() => new { TrailingDistanceFunction }); var tci_ = MonoidsCore.ToFunc(() => TradeConditionsInfo((d, p, n) => new { n, v = d(), d }).ToArray()); var toai = MonoidsCore.ToFunc(() => TradeOpenActionsInfo((d, n) => new { n, d }).ToArray()); Action setLevels = () => { if (IsAsleep || IsHedgedTrading || isHedgeChild) { TradingMacrosByPair() .OrderByDescending(tm => tm._RatesMax - tm._RatesMin) .Take(1) .ForEach(tm => { var offset = (tm._RatesMax - tm._RatesMin) / 20; SellLevel.Rate = tm._RatesMax + offset; BuyLevel.Rate = tm._RatesMin - offset; }); } else if (!TradeConditionsHaveSetCorridor()) { TradeConditionsCanSetCorridor() .Where(td => td.HasAny()) .ForEach(_ => SetTradeLevelsToLevelBy(GetTradeLevel)()); } if (IsTrader) { adjustExitLevels2(); } }; #region FirstTime if (firstTime && IsTrader) { WorkflowStep = ""; Log = new Exception(conditions() + ""); ResetTakeProfitManual(); #region onCloseTradeLocal onCanTradeLocal = canTrade => canTrade || Trades.Any(); var canTradeOff = !IsAutoStrategy; #region turnItOff Action <bool, Action> turnItOff = (should, a) => _buySellLevels .Where(_ => should) .Do(sr => { //if(!TradeConditionsHave(Tip2Ok)) sr.InManual = false; sr.CanTrade = !IsAutoStrategy; sr.TradesCount = TradeCountStart; }) .ToArray() .Take(1) .Do(_ => { UnFreezeCorridorStartDate(); }) .Where(_ => a != null) .ForEach(_ => a()); #endregion var hasTradeCountOff = _buySellLevels.Where(sr => sr.TradesCount < -TradeCountMax); onCloseTradeLocal += t => { //if(!HaveTrades()) { if (_buySellLevels.All(sr => sr.InManual && !sr.CanTrade)) { _buySellLevelsForEach(sr => sr.InManual = false); } if (minPLOk(t) || hasTradeCountOff.Any()) { BuyLevel.InManual = SellLevel.InManual = false; turnItOff(true, () => { if (canTradeOff) { IsTradingActive = false; } }); } if (false && CurrentGrossInPipTotal > 0) { BroadcastCloseAllTrades(); } BuyCloseLevel.InManual = SellCloseLevel.InManual = false; CorridorStartDate = null; //} setLevels(); }; #endregion Action <Trade> canTradeByTradeCount = t => hasTradeCountOff .Take(1) .ForEach(_ => { _buySellLevels .ForEach(sr => { sr.CanTrade = false; sr.TradesCount = TradeCountStart; }); }); onOpenTradeLocal += t => { canTradeByTradeCount(t); toai().ForEach(x => { Log = new Exception(nameof(TradeOpenAction) + ": " + x.n); x.d(t); }); }; } #endregion setLevels(); if (IsTrader) { exitFunc(); try { TradeDirectionTriggersRun(); TradeConditionsTrigger(); } catch (Exception exc) { Log = exc; } } } break; #endregion } if (firstTime) { firstTime = false; ResetBarsCountCalc(); ForEachSuppRes(sr => sr.ResetPricePosition()); LogTrades = !IsInVirtualTrading; } }; #endregion #endregion #region On Trade Close _strategyExecuteOnTradeClose = t => { if (!Trades.Any() && isCurrentGrossOk()) { CorridorStartDate = null; CorridorStopDate = DateTime.MinValue; } if (onCloseTradeLocal != null) { onCloseTradeLocal(t); } if (TurnOffOnProfit && t.PL >= PriceSpreadAverageInPips) { Strategy = Strategy & ~Strategies.Auto; } CloseAtZero = false; }; #endregion #region On Trade Open _strategyExecuteOnTradeOpen = trade => { SuppRes.ForEach(sr => sr.ResetPricePosition()); onOpenTradeLocal?.Invoke(trade); IsTradingActive = IsTradingActive || IsInVirtualTrading; }; #endregion #region _adjustEnterLevels Action setLevelPrices = () => { try { if (IsTradingActive) { BuyLevel.SetPrice(enter(true)); SellLevel.SetPrice(enter(false)); BuyCloseLevel.SetPrice(CurrentExitPrice(true)); SellCloseLevel.SetPrice(CurrentExitPrice(false)); } else { SuppRes.ForEach(sr => sr.ResetPricePosition()); } } catch (Exception exc) { Log = exc; } }; _adjustEnterLevels += setLevelPrices; _adjustEnterLevels += adjustEnterLevels; _adjustEnterLevels += () => turnOff(() => _buySellLevelsForEach(sr => { if (IsAutoStrategy) { sr.CanTradeEx = false; } })); _adjustEnterLevels += () => exitFunc()(); _adjustEnterLevels += setLevelPrices; _adjustEnterLevels += () => { if (runOnce != null && runOnce()) { runOnce = null; } }; #endregion } #region if (!IsInVitualTrading) { if (!IsInVirtualTrading) { this.TradesManager.TradeClosed += TradeCloseHandler; this.TradesManager.TradeAdded += TradeAddedHandler; } #endregion #endregion #region ============ Run ============= _adjustEnterLevels(); #endregion }