private void AssignLeaveRulesAndStart() { if (_leaveStrategy == null) { throw new NullReferenceException("leaveStrategy"); } _leaveStrategy.WhenNewMyTrade() .Do(mt => { var sign = 1; if (_leaveStrategy.QuotingSide == Sides.Sell) { sign = -1; } PositionAndMoneySyncIncrementation(mt.Trade.Volume * sign, mt.Trade.Volume * mt.Trade.Price * sign * -1); _enterStrategy.SafeStop(); }) .Until(() => !_isLeaverActivated) .Apply(this); _leaveStrategy.PrimaryStrategyStopped += () => { ChildStrategies.Remove(_leaveStrategy); _isLeaverActivated = false; }; MarkStrategyLikeChild(_leaveStrategy); ChildStrategies.Add(_leaveStrategy); }
private void OnChildStrategiesAdded(Strategy strategy) { var rule = strategy .WhenStopped() .Do(s => { if (FinishMode == BasketStrategyFinishModes.First) { if (FirstFinishStrategy == null) { FirstFinishStrategy = s; Stop(); } } else { if (ChildStrategies.All(child => child.ProcessState != ProcessStates.Started)) { Stop(); } } }) .Once() .Apply(this); rule.UpdateName(rule.Name + " (BasketStrategy.OnChildStrategiesAdded)"); }
private void OnNewOrderTrades(IEnumerable <MyTrade> trades) { // для каждой сделки добавляем защитную пару стратегии /* * var protectiveStrategies = trades.Select(t => * { * // выставляет стоп-лосс в deflevel пунктов * var stopLoss = new StopLossStrategy(t, deflevel); * stopLoss.IsTrailing = true; * return stopLoss; * }); * * //ChildStrategies.AddRange(protectiveStrategies); * foreach (var st in protectiveStrategies) * ChildStrategies.Add(st); * */ StopLossStrategy stopLoss = new StopLossStrategy(trades.ToArray <MyTrade>()[0], 40); stopLoss.IsTrailing = true; stopLoss.WhenError().Do(() => { this.AddInfoLog("ololo"); }); stopLoss.WhenNewMyTrades().Do(() => { this.AddInfoLog("ololo111"); }); ChildStrategies.Add(stopLoss); }
public EquityStrategy(IEnumerable <Order> orders, IDictionary <Security, decimal> openedPositions) { _orders = orders.GroupBy(o => o.Time).ToDictionary(g => g.Key, g => g.ToArray()); _childStrategies = orders.ToDictionary(GetKey, o => new Strategy { Portfolio = o.Portfolio, Security = o.Security, Position = openedPositions.TryGetValue2(o.Security) ?? 0, }); ChildStrategies.AddRange(_childStrategies.Values); }
protected override void OnStarted() { DoStrategyPreparation(new Security[] { Security }, new Security[] { Security }, new Portfolio[] { Portfolio }); if (_spread <= 0) { throw new ArgumentException("Spread cannot be below zero: " + _spread); } if (_lot <= 0) { throw new ArgumentException("Lot cannot be below zero: " + _lot); } if (Security.PriceStep == null) { throw new ArgumentException("Cannot read security price set, probably data still loading... :" + Security.PriceStep); } if (LimitedFuturesValueAbs < 0) { throw new ArgumentException("limitation of futures positions is established by value >=0 : " + LimitedFuturesValueAbs); } if (_sideForEnterToPosition == Sides.Sell) { LimitedFuturesValueAbs = LimitedFuturesValueAbs != 0 ? LimitedFuturesValueAbs * -1 : decimal.MinValue; } else { LimitedFuturesValueAbs = LimitedFuturesValueAbs != 0 ? LimitedFuturesValueAbs : decimal.MaxValue; } md = GetMarketDepth(Security); TimingController.SetTimingMethod(SpreadingProcess); Security.WhenMarketDepthChanged(Connector) .Do(() => { TimingController.TimingMethodHappened(); SpreadingProcess(); }) .Apply(this); this.WhenStopping() .Do(() => { ChildStrategies.Clear(); }) .Once() .Apply(this); base.OnStarted(); }
public virtual void PrimaryStopping() { TimingController.StopTimingControl(); var totalChildCount = ChildStrategies.Count; try { if (ChildStrategies?.Count > 0) { ChildStrategies.ForEach(ps => { Task.Run(() => { var curStrategy = ps as PrimaryStrategy; if (curStrategy == null) { return; } curStrategy.PrimaryStrategyStopped += () => _closedChildCounter++; curStrategy.CancelActiveOrders();//TODO ещё одна попытка решить проблему залипающих ордеров в терминале после остановки стратегии curStrategy.PrimaryStopping(); }); }); } while (totalChildCount != _closedChildCounter) { /*NOP*/ } Stop(); _closedChildCounter = 0; } catch (Exception e1) { this.AddErrorLog(e1); } }
private void ProcessCandle(Candle candle) { // если наша стратегия в процессе остановки if (ProcessState == ProcessStates.Stopping) { // отменяем активные заявки CancelActiveOrders(); return; } // добавляем новую свечу LongSma.Process(candle); ShortSma.Process(candle); // вычисляем новое положение относительно друг друга var isShortLessThenLong = ShortSma.GetCurrentValue() < LongSma.GetCurrentValue(); // если произошло пересечение if (_isShortLessThenLong != isShortLessThenLong) { // если короткая меньше чем длинная, то продажа, иначе, покупка. var direction = isShortLessThenLong ? Sides.Sell : Sides.Buy; // вычисляем размер для открытия или переворота позы var volume = Position == 0 ? Volume : Position.Abs() * 2; // регистрируем заявку (обычным способом - лимитированной заявкой) //RegisterOrder(this.CreateOrder(direction, (decimal)Security.GetCurrentPrice(direction), volume)); // переворачиваем позицию через котирование var strategy = new MarketQuotingStrategy(direction, volume); ChildStrategies.Add(strategy); // запоминаем текущее положение относительно друг друга _isShortLessThenLong = isShortLessThenLong; } }
private void DoHedge(decimal currentDelta, decimal deltaStep) { QuoterStrategy mqs = null; var hedgeSize = (currentDelta / deltaStep).PrepareSizeToTrade(); if (currentDelta > 0) { hedgeSize = hedgeSize.ShrinkSizeToTrade(Sides.Sell, _futuresPosition, MinFuturesPositionVal); if (hedgeSize <= 0) { return; } mqs = new MarketQuoterStrategy(Sides.Sell, hedgeSize, Security.GetMarketPrice(Sides.Sell)); _futuresPosition -= hedgeSize; } if (currentDelta < 0) { hedgeSize = hedgeSize.ShrinkSizeToTrade(Sides.Buy, _futuresPosition, MaxFuturesPositionVal); if (hedgeSize <= 0) { return; } mqs = new MarketQuoterStrategy(Sides.Buy, hedgeSize, Security.GetMarketPrice(Sides.Buy)); _futuresPosition += hedgeSize; } MarkStrategyLikeChild(mqs); ChildStrategies.Add(mqs); }
private void ProcessCandle(Candle candle) { // если наша стратегия в процессе остановки if (ProcessState == ProcessStates.Stopping) { // отменяем активные заявки CancelActiveOrders(); return; } this.AddInfoLog(LocalizedStrings.Str2177Params.Put(candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume)); // добавляем новую свечу var longValue = LongATR.Process(candle); var shortValue = ShortATR.Process(candle); if (Position < 0) { if (maxPrice > candle.ClosePrice) { maxPrice = candle.ClosePrice; } } // вычисляем новое положение относительно друг друга // var isShortLessThenLong = ShortSma.GetCurrentValue() < LongSma.GetCurrentValue(); if (-maxPrice + candle.ClosePrice > protectLevel && needProtect) { var price = Security.GetMarketPrice(Connector, Sides.Buy); // регистрируем псевдо-маркетную заявку - лимитная заявка с ценой гарантирующей немедленное исполнение. if (price != null) { RegisterOrder(this.CreateOrder(Sides.Buy, price.Value, Volume)); needProtect = false; } } // если индикаторы заполнились if (LongATR.Container.Count >= LongATR.Length) { if (LongATR.GetCurrentValue <int>() > ShortATR.GetCurrentValue <int>() && Position == 0) { // если короткая меньше чем длинная, то продажа, иначе, покупка. var direction = Sides.Sell; // вычисляем размер для открытия или переворота позы var volume = Volume; if (!SafeGetConnector().RegisteredMarketDepths.Contains(Security)) { var price = Security.GetMarketPrice(Connector, direction); // регистрируем псевдо-маркетную заявку - лимитная заявка с ценой гарантирующей немедленное исполнение. if (price != null) { RegisterOrder(this.CreateOrder(direction, price.Value, volume)); needProtect = true; protectLevel = LongATR.GetCurrentValue <int>() * 3; } } else { // переворачиваем позицию через котирование var strategy = new MarketQuotingStrategy(direction, volume) { WaitAllTrades = true, }; ChildStrategies.Add(strategy); } } } _myTrades.Clear(); var dict = new Dictionary <IChartElement, object> { { _candlesElem, candle }, }; _chart.Draw(candle.OpenTime, dict); }
private void ProcessCandle(Candle candle) { // если наша стратегия в процессе остановки if (ProcessState == ProcessStates.Stopping) { // отменяем активные заявки CancelActiveOrders(); return; } this.AddInfoLog(LocalizedStrings.Str2177Params.Put(candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume)); // добавляем новую свечу var longValue = LongSma.Process(candle); var shortValue = ShortSma.Process(candle); // вычисляем новое положение относительно друг друга var isShortLessThenLong = ShortSma.GetCurrentValue() < LongSma.GetCurrentValue(); // если произошло пересечение if (_isShortLessThenLong != isShortLessThenLong) { // если короткая меньше чем длинная, то продажа, иначе, покупка. var direction = isShortLessThenLong ? Sides.Sell : Sides.Buy; // вычисляем размер для открытия или переворота позы var volume = Position == 0 ? Volume : Position.Abs().Min(Volume) * 2; if (!SafeGetConnector().RegisteredMarketDepths.Contains(Security)) { var price = Security.GetMarketPrice(Connector, direction); // регистрируем псевдо-маркетную заявку - лимитная заявка с ценой гарантирующей немедленное исполнение. if (price != null) { RegisterOrder(this.CreateOrder(direction, price.Value, volume)); } } else { // переворачиваем позицию через котирование var strategy = new MarketQuotingStrategy(direction, volume) { WaitAllTrades = true, }; ChildStrategies.Add(strategy); } // запоминаем текущее положение относительно друг друга _isShortLessThenLong = isShortLessThenLong; } var trade = _myTrades.FirstOrDefault(); _myTrades.Clear(); var dict = new Dictionary <IChartElement, object> { { _candlesElem, candle }, { _shortElem, shortValue }, { _longElem, longValue }, { _tradesElem, trade } }; _chart.Draw(candle.OpenTime, dict); }
protected override void OnStarted() { if (SecurityWithSignalToClose == null) { DoStrategyPreparation(new Security[] { }, new Security[] { Security }, new Portfolio[] { Portfolio }); } else { DoStrategyPreparation(new Security[] { }, new Security[] { Security, SecurityWithSignalToClose }, new Portfolio[] { Portfolio }); } if (Volume <= 0 || _priceToClose <= 0) { throw new ArgumentException( $"Volume: {Volume} or price to close: {_priceToClose} cannot be below zero"); } ; this.WhenPositionChanged() .Do(() => { if (Math.Abs(Position) >= Volume) { PrimaryStopping(); } }) .Apply(this); //не проверяем время, т.к. правило выполняется Once() TimingController.SetTimingUnnecessary(); if (SecurityWithSignalToClose == null) { var md = GetMarketDepth(Security); Security.WhenMarketDepthChanged(Connector) .Do(() => { var mqs = new MarketQuoterStrategy(_strategyOrderSide, Volume, _priceToClose); mqs.WhenStopped() .Do(this.Stop) .Once() .Apply(this); MarkStrategyLikeChild(mqs); ChildStrategies.Add(mqs); }) .Once() .Apply(this); } else { PrimaryStrategy mqs = null; var md = GetMarketDepth(SecurityWithSignalToClose); var mqsStartRule = SecurityWithSignalToClose .WhenMarketDepthChanged(Connector) .Do(() => { if (!IsTradingTime()) { return; } //котировки специально развернуты неверно - как только была сделка на графике (ударили в аск или налили в бид) - закрываемся if (_securityDesirableDirection == PriceDirection.Up && md.BestAsk.Price >= _priceToClose || _securityDesirableDirection == PriceDirection.Down && md.BestBid.Price <= _priceToClose) { // пока делаем по любой цене, как только сработает условие mqs = new MarketQuoterStrategy(_strategyOrderSide, Volume, Security.GetMarketPrice(_strategyOrderSide)); mqs.WhenStopped() .Do(this.Stop) .Once() .Apply(this); MarkStrategyLikeChild(mqs); ChildStrategies.Add(mqs); } }) .Until(() => mqs != null) .Apply(this); this.WhenStopping() .Do(() => { /*NOP*/ }) .Apply(this) .Exclusive(mqsStartRule); } base.OnStarted(); }
private void AssignEnterRulesAndStart() { if (_enterStrategy == null) { throw new NullReferenceException("strategy, when was trying to assign enter rules"); } Security.WhenMarketDepthChanged(Connector) .Do(md => { if (_lastQuoterPrice == 0) { return; } if (md.BestBid == null || md.BestAsk == null) { return; } var bestQuote = md.GetSuitableBestLimitQuote(_enterStrategy.QuotingSide); if (_enterStrategy.QuotePriceShift != 0) { if (_lastQuoterPrice != bestQuote.Price || md.BestPair.SpreadPrice != null && md.BestPair.SpreadPrice.Value <= _spread) { _lastQuoterPrice = 0; _enterStrategy.SafeStop(); } } if (_enterStrategy.QuotePriceShift == 0 && CheckIfSpreadChangedOrItsParts(md.BestPair)) { _enterStrategy.SafeStop(); } }) .Until(() => !_isEnterActivated) .Apply(this); _enterStrategy.WhenOrderRegistered() .Do(o => { _lastQuoterPrice = o.Price; }) .Until(() => !_isEnterActivated) .Apply(this); _enterStrategy.WhenNewMyTrade() .Do(mt => { var sign = 1; if (_enterStrategy.QuotingSide == Sides.Sell) { sign = -1; } PositionAndMoneySyncIncrementation(mt.Trade.Volume * sign, mt.Trade.Volume * mt.Trade.Price * sign * -1); _leaveStrategy.SafeStop(); }) .Until(() => !_isEnterActivated) .Apply(this); _enterStrategy.PrimaryStrategyStopped += () => { ChildStrategies.Remove(_enterStrategy); _isEnterActivated = false; }; MarkStrategyLikeChild(_enterStrategy); ChildStrategies.Add(_enterStrategy); }
protected void ProcessFinCandle(Candle candle) { if (ProcessState == ProcessStates.Stopping) { // отменяем активные заявки CancelActiveOrders(); return; } //this.AddInfoLog("Новая свеча {0}: {1};{2};{3};{4}; объем {5}".Put(candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume)); // добавляем новую свечку LongATR.Process(candle); ShortATR.Process(candle); PLB.Process(candle); int tt = PLB.GetCurrentValue <int>(); if ((double)candle.ClosePrice < buyprice - deflevel && buyprice > 0) { } //+! костыльная проверка что индикатор заполнен. // нужно всегда заполнять перед торговлей if (LongATR.Container.Count >= LongATR.Length) { if (LongATR.GetCurrentValue <int>() > ShortATR.GetCurrentValue <int>() && this.Position == 0) { var direction = OrderDirections.Buy; buyprice = (double)candle.ClosePrice; //спизжено из стоп лос стретеджи //var longPos = this.BuyAtMarket(); //// регистрируем правило, отслеживающее появление новых сделок по заявке //longPos // .WhenNewTrades() // .Do(OnNewOrderTrades) // .Apply(this); //// отправляем заявку на регистрацию //RegisterOrder(longPos); double dl = 2.5 * ShortATR.GetCurrentValue <int>(); deflevel = (int)(dl + 0.5); Order longPos; if (!((EmulationTrader)Trader).MarketEmulator.Settings.UseMarketDepth) { // регистрируем псевдо-маркетную заявку - лимитная заявка с ценой гарантирующей немедленное исполнение. longPos = this.CreateOrder(direction, Security.GetMarketPrice(direction), Volume); RegisterOrder(longPos); } else { // переворачиваем позицию через котирование var strategy = new MarketQuotingStrategy(direction, Volume) { WaitAllTrades = true, }; ChildStrategies.Add(strategy); } // если произошло пересечение //if (_isShortLessThenLong != isShortLessThenLong) //{ // если короткая меньше чем длинная, то продажа, иначе, покупка. // var direction = isShortLessThenLong ? OrderDirections.Sell : OrderDirections.Buy; // if (!((EmulationTrader)Trader).MarketEmulator.Settings.UseMarketDepth) // { // регистрируем псевдо-маркетную заявку - лимитная заявка с ценой гарантирующей немедленное исполнение. // RegisterOrder(this.CreateOrder(direction, Security.GetMarketPrice(direction), Volume)); // } // else // { // переворачиваем позицию через котирование // var strategy = new MarketQuotingStrategy(direction, Volume) // { // WaitAllTrades = true, // }; // ChildStrategies.Add(strategy); // } // запоминаем текущее положение относительно друг друга // _isShortLessThenLong = isShortLessThenLong; //} //+! щас будет костыльный параметр 2.5 на ATR в стопах } } }