private void AreaCloserPositionThread() { while (true) { Thread.Sleep(1000); if (_positionToClose == null) { continue; } if (DateTime.Now < _timeToClose) { continue; } if (_positionToClose.OpenVolume != 0 && _positionToClose.Direction == Side.Buy) { _tab.SetNewLogMessage("Кроем позицию по эмулятору. Номер позиции: " + _positionToClose.Number, LogMessageType.System); _tab.CloseAtLimit(_positionToClose, _tab.PriceBestAsk - _tab.Securiti.PriceStep * 10, _positionToClose.OpenVolume); } else if (_positionToClose.OpenVolume != 0 && _positionToClose.Direction == Side.Sell) { _tab.SetNewLogMessage("Кроем позицию по эмулятору. Номер позиции: " + _positionToClose.Number, LogMessageType.System); _tab.CloseAtLimit(_positionToClose, _tab.PriceBestAsk + _tab.Securiti.PriceStep * 10, _positionToClose.OpenVolume); } _positionToClose = null; } }
private void AlligatorTrend_ParametrsChangeByUser() { if (AlligatorFastLenght.ValueInt > AlligatorMiddleLenght.ValueInt || AlligatorFastLenght.ValueInt > AlligatorSlowLenght.ValueInt) { _tab.SetNewLogMessage("ParametrsChangeByUser: Недопустимые значения параметров алигатора." + " Длина быстрого алигатора должна быть меньше длины среднего и медленного алигатора", Logging.LogMessageType.Error); return; } if (AlligatorMiddleLenght.ValueInt > AlligatorSlowLenght.ValueInt) { _tab.SetNewLogMessage("ParametrsChangeByUser: Недопустимые значения параметров алигатора." + " Длина среднего алигатора должна быть меньше длины медленного алигатора", Logging.LogMessageType.Error); return; } if (_alligator.ParametersDigit[0].Value != AlligatorSlowLenght.ValueInt || _alligator.ParametersDigit[1].Value != AlligatorFastLenght.ValueInt || _alligator.ParametersDigit[2].Value != AlligatorMiddleLenght.ValueInt) { _alligator.ParametersDigit[0].Value = AlligatorSlowLenght.ValueInt; _alligator.ParametersDigit[1].Value = AlligatorFastLenght.ValueInt; _alligator.ParametersDigit[2].Value = AlligatorMiddleLenght.ValueInt; _alligator.Reload(); } }
/// <summary> /// Обработчик события изменения нетто позиции для инструмента 1 /// </summary> /// <param name="position"></param> private void _tab1_PositionNetVolumeChangeEvent(Position position) { if (position.WaitVolume != 0) { return; } decimal sellPrice2 = _tab2.PriceBestBid; decimal volume2 = Math.Round(position.OpenVolume * sellPrice2, Decimals); _tab2.SellAtLimit(position.OpenVolume, sellPrice2, volume2.ToString()); _tab1.GetJournal().DeletePosition(position); _tab1.SetNewLogMessage($"tab1 buy, sec1 {position.OpenVolume}", LogMessageType.System); }
/// <summary> /// Получить количество десятичных знаков для панели /// </summary> /// <param name="tab">Панель </param> /// <returns></returns> public static int GetRoundVolumeDecimals(BotTabSimple tab) { if (tab.Connector.MyServer.ServerType == ServerType.BinanceFutures) { switch (tab.Securiti.Name) { case "ETHUSDT": return(3); case "EOSUSDT": return(1); case "LINKUSDT": return(2); case "XMRUSDT": return(3); case "ATOMUSDT": return(2); case "TRXUSDT": return(0); case "ADAUSDT": return(0); case "BNBUSDT": return(2); case "BTCUSDT": return(3); case "ETCUSDT": return(2); case "BCHUSDT": return(3); case "ZECUSDT": return(3); case "LTCUSDT": return(3); case "XTZUSDT": return(1); case "XRPUSDT": return(1); case "XLMUSDT": return(0); case "ONTUSDT": return(1); case "IOTAUSDT": return(1); case "BATUSDT": return(1); case "VETUSDT": return(0); case "NEOUSDT": return(2); default: tab.SetNewLogMessage("Для инструмента: " + tab.Securiti.Name + " необходимо описать округление ", Logging.LogMessageType.Error); break; } } return(0); }
/// <summary> /// попробовать закрыть позицию /// </summary> private void TryClosePosition(Position position, List <Candle> candles) { if (EmulatorIsOn) { int currentEmuPos = GetCurrentPosition(); if (currentEmuPos == 0 || currentEmuPos == 1 && position.Direction == Side.Sell || currentEmuPos == -1 && position.Direction == Side.Buy) { _tab.SetNewLogMessage("Кроем позицию по эмулятору. Номер позиции: " + position.Number, LogMessageType.System); // Выход по эмулятору! позиции нет. Нужно закрывать полюбой цене _tab.CloseAllOrderToPosition(position); _timeToClose = DateTime.Now.AddSeconds(3); _positionToClose = position; return; } } // первый выход по проколу if (Shoulderette(candles.Count - 1, candles)) { // если произошёл прокол и мы заработали больше 20% if (position.EntryPrice * 1.2m <= candles[candles.Count - 1].Close) { _tab.CloseAtLimit(position, candles[candles.Count - 1].Close - SlipageCloseFirst * _tab.Securiti.PriceStep, position.OpenVolume); //Sell(_settings.Position, _myCandles[_myCandles.Length - 1].ClosePrice); return; } } // второй выход по стопам if (position.Direction == Side.Buy) { decimal priceEtalon = Math.Round(((Line)_chandelier).Values[((Line)_chandelier).Values.Count - 1], _tab.Securiti.Decimals); if (_tab.Securiti.Decimals == 0) { priceEtalon = Math.Truncate(((Line)_chandelier).Values[((Line)_chandelier).Values.Count - 1]); } decimal priceOrder = priceEtalon - _tab.Securiti.PriceStep * SlipageCloseFirst; // ЗДЕСЬ!!!!!!!!!!!!!! decimal priceRedLine = priceEtalon + _tab.Securiti.PriceStep * SlipageReversClose; if (priceRedLine - _tab.Securiti.PriceStep * 10 > _tab.PriceBestAsk) { _tab.CloseAtLimit(position, _tab.PriceBestAsk, position.OpenVolume); return; } _tab.CloseAtStop(position, priceRedLine, priceOrder); if (StartProgram != StartProgram.IsTester && AlertIsOn) { _alert.PriceActivation = priceRedLine + SlipageToAlert * _tab.Securiti.PriceStep; _alert.TypeActivation = PriceAlertTypeActivation.PriceLowerOrEqual; _alert.MessageIsOn = true; _alert.MusicType = AlertMusic.Duck; _alert.Message = "Приближаемся к точке выхода"; _alert.IsOn = true; } } }
/// <summary> /// Обработка события закрытия свечи - базовая торговая логика /// </summary> /// <param name="candles">Список свечей</param> private void Tab_CandleFinishedEvent(List <Candle> candles) { if (Regime.ValueString == "Off") { return; } // сохраняем длину болинджера int bollingerPeriod = (int)_bollinger.ParametersDigit[0].Value; // проверка на достаточное количество свечек и наличие данных в болинджере if (candles == null || candles.Count < bollingerPeriod + 5 || _bollinger.DataSeries[0].Values == null || _bollinger.DataSeries[1].Values == null) { return; } // сохраняем последние значения параметров цены и болинджера для дальнейшего сокращения длины кода _lastPrice = candles[candles.Count - 1].Close; _highLastCandle = candles[candles.Count - 1].High; _lowLastCandle = candles[candles.Count - 1].Low; _upBollinger = _bollinger.DataSeries[0].Values[_bollinger.DataSeries[0].Values.Count - 2]; _downBollinger = _bollinger.DataSeries[1].Values[_bollinger.DataSeries[1].Values.Count - 2]; // проверка на корректность последних значений цены и болинджера if (_lastPrice <= 0 || _upBollinger <= 0 || _downBollinger <= 0) { _tab.SetNewLogMessage("Tab_CandleFinishedEvent: цена или линии болинждера" + " меньше или равны нулю.", Logging.LogMessageType.Error); return; } // берем все открытые позиции, которые дальше будем проверять на условие закрытия List <Position> openPositions = _tab.PositionsOpenAll; for (int i = 0; openPositions.Count != 0 && i < openPositions.Count; i++) { // если позиция не открыта, то ничего не делаем if (openPositions[i].State != PositionStateType.Open) { continue; } // выхода из позиции по пробою индикатора Болинжер if (MethodOutOfPosition.ValueString == "ChannelCenter") { OutOfPositionByCenterChannel(openPositions[i]); } else { OutOfPositionByBollinger(openPositions[i]); } // установка стопа для перевода позиции в безубыток if (OnStopForBreakeven.ValueBool) { SetStopForBreakeven(openPositions[i]); } } // если включен режим "OnlyClosePosition", то к открытию позиций не переходим if (Regime.ValueString == "OnlyClosePosition") { return; } // проверка возможности открытия позиции (робот открывает только одну позицию) if (openPositions.Count == 0) { // условие входа в лонг: пробитие ценой верхнего болинджера и с учетом фильтра if (_lastPrice > _upBollinger && candles[candles.Count - 2].Close < _bollinger.DataSeries[0].Values[_bollinger.DataSeries[0].Values.Count - 3] && Regime.ValueString != "OnlyShort") { OpenLong(); } // условие входа в шорт: пробитие ценой нижнего болинджера и с учетом фильтра else if (_lastPrice < _downBollinger && candles[candles.Count - 2].Close > _bollinger.DataSeries[1].Values[_bollinger.DataSeries[1].Values.Count - 3] && Regime.ValueString != "OnlyLong") { OpenShort(); } } return; }
/// <summary> /// проверить условия на вход в позицию /// </summary> private void TryOpenPosition(List <Candle> candles) { decimal damping; decimal avgHigh2; decimal avgLow3; decimal avgLow2; decimal avgHigh3; decimal avgHighShifted; decimal avgLowShifted; try { if (((MovingAverage)_smaHigh4Period).Values.Count - 1 - 10 < 0) { return; } damping = ((Line)_dampIndex).Values[((Line)_dampIndex).Values.Count - 1]; avgHigh2 = ((MovingAverage)_smaHigh2Period).Values[((MovingAverage)_smaHigh2Period).Values.Count - 1]; // SMA.Series(High, 2); avgLow3 = ((MovingAverage)_smaLow3Period).Values[((MovingAverage)_smaLow3Period).Values.Count - 1]; //SMA.Series(Low, 3); avgLow2 = ((MovingAverage)_smaLow3Period).Values[((MovingAverage)_smaLow3Period).Values.Count - 1]; //SMA.Series(Low, 3); avgHigh3 = ((MovingAverage)_smaHigh3Period).Values[((MovingAverage)_smaHigh3Period).Values.Count - 1]; //SMA.Series(High, 3); avgHighShifted = ((MovingAverage)_smaHigh4Period).Values[((MovingAverage)_smaHigh4Period).Values.Count - 1 - 10]; //SMA.Series(High, 4) >> 10; avgLowShifted = ((MovingAverage)_smaLow4Period).Values[((MovingAverage)_smaLow4Period).Values.Count - 1 - 10]; //SMA.Series(Low, 4) >> 10; } catch (Exception error) { _tab.SetNewLogMessage(error.ToString(), LogMessageType.Error); return; } if (EmulatorIsOn) { int currentEmuPos = GetCurrentPosition(); if (currentEmuPos != 0) { return; } } if (damping < 1 && (candles[candles.Count - 1].Close > avgHigh2) && (avgLow3 > avgHighShifted)) { _tab.SetNewLogMessage("Системный вход в лонг. Время: " + candles[candles.Count - 1].TimeStart, LogMessageType.Signal); if (StartProgram == StartProgram.IsTester) { _tab.BuyAtMarket(Volume); } else { _tab.BuyAtLimit(Volume, candles[candles.Count - 1].Close + _tab.Securiti.PriceStep * SlipageOpenFirst); // ЗДЕСЬ!!!!!!!!!!!!!! } return; } else if (damping < 1 && (candles[candles.Count - 1].Close < avgLow2) && (avgHigh3 < avgLowShifted)) { _tab.SetNewLogMessage("Системный вход в шорт. Время: " + candles[candles.Count - 1].TimeStart, LogMessageType.Signal); if (StartProgram == StartProgram.IsTester) { _tab.SellAtMarket(Volume); } else { _tab.SellAtLimit(Volume, candles[candles.Count - 1].Close - _tab.Securiti.PriceStep * SlipageOpenFirst); // ЗДЕСЬ!!!!!!!!!!!!!! } return; } else if (damping <= 1) { if (AlertIsOn) { AlertMessageManager.ThrowAlert(Properties.Resources.Duck, NameStrategyUniq, "Внимание! DI меньше 1, но входа не произошло. На следующей свече возможно открытие"); } } }
/// <summary> /// Открытие по паттерну /// </summary> /// <param name="indicators">Индикаторы</param> /// <param name="candles">Свечи</param> /// <param name="patterns">Список паттернов</param> private void OpenByPattrn(List <IIndicator> indicators, List <Candle> candles, List <string> patterns) { if (!ValidateParams()) { return; } if (!CanOpenPosition()) { return; } if (candles.Count < 2) { return; } bool CanFindPattern = false; for (int i = 1; i <= 1; i++) { Candle candle = candles[candles.Count - i]; List <PriceLevleLine.levlel> lvl = PriceLevleLine.LevleData.FindAll(x => x.Value <= candle.High && x.Value >= candle.Low); if (lvl != null && lvl.Count > 0) { List <PriceLevleLine.levlel> filter = GetFilterlvl(); foreach (PriceLevleLine.levlel l in lvl) { if (filter != null && filter.Find(f => f.Value == l.Value) != null) { continue; } CanFindPattern = true; } } } if (TradeSide == Side.Buy && candles[candles.Count - 2].Close < LastSessionEndPrice) { CanFindPattern = false; } if (TradeSide == Side.Sell && candles[candles.Count - 2].Close > LastSessionEndPrice) { CanFindPattern = false; } if (!CanFindPattern) { return; } // открытие позиций по патерну List <Pattern> signal = Pattern.GetValidatePatterns(candles, indicators, patterns); if (signal.Count > 0 && signal[0].isPattern) { if (signal.Count != 0 && signal[0].isPattern) { if (signal[0].Side == TradeSide) { _tab.SetNewLogMessage("Открытие по патерну " + signal[0].GetType().Name, LogMessageType.Signal); OpenPosition(signal[0].Side, candles[candles.Count - 1].Close, signal[0].GetType().Name); } } } }
/// <summary> /// проверить условия для выхода из позиции /// </summary> private void TryClosePosition(Position position, List <Candle> candles) { if (EmulatorIsOn) { int currentEmuPos = GetCurrentPosition(); if (currentEmuPos == 0 || currentEmuPos == 1 && position.Direction == Side.Sell || currentEmuPos == -1 && position.Direction == Side.Buy) { _tab.SetNewLogMessage("Кроем позицию по эмулятору. Номер позиции: " + position.Number, LogMessageType.System); // Выход по эмулятору! позиции нет. Нужно закрывать полюбой цене _tab.CloseAllOrderToPosition(position); _timeToClose = DateTime.Now.AddSeconds(3); _positionToClose = position; return; } } // выход по стопам if (position.Direction == Side.Buy) { decimal price = GetPriseStop(Side.Buy, candles, candles.Count - 1); if (price == 0) { return; } decimal priceOrder = price - _tab.Securiti.PriceStep * SlipageCloseFirst; // ЗДЕСЬ!!!!!!!!!!!!!! decimal priceRedLine = price + _tab.Securiti.PriceStep * SlipageReversClose; if (priceRedLine - _tab.Securiti.PriceStep * 10 > _tab.PriceBestAsk) { _tab.CloseAtLimit(position, _tab.PriceBestAsk, position.OpenVolume); return; } if (position.StopOrderRedLine == 0 || position.StopOrderRedLine < priceRedLine) { _tab.CloseAtStop(position, priceRedLine, priceOrder); if (StartProgram != StartProgram.IsTester && AlertIsOn) { _alert.PriceActivation = priceRedLine + SlipageToAlert * _tab.Securiti.PriceStep; _alert.TypeActivation = PriceAlertTypeActivation.PriceLowerOrEqual; _alert.MessageIsOn = true; _alert.MusicType = AlertMusic.Duck; _alert.Message = "Приближаемся к точке выхода"; _alert.IsOn = true; } } else if (position.StopOrderIsActiv == false) { if (position.StopOrderRedLine - _tab.Securiti.PriceStep * 10 > _tab.PriceBestAsk) { _tab.CloseAtLimit(position, _tab.PriceBestAsk, position.OpenVolume); return; } position.StopOrderIsActiv = true; } } if (position.Direction == Side.Sell) { decimal price = GetPriseStop(Side.Sell, candles, candles.Count - 1); if (price == 0) { return; } decimal priceOrder = price + _tab.Securiti.PriceStep * SlipageCloseFirst; // ЗДЕСЬ!!!!!!!!!!!!!! decimal priceRedLine = price - _tab.Securiti.PriceStep * SlipageReversClose; if (priceRedLine + _tab.Securiti.PriceStep * 10 < _tab.PriceBestAsk) { _tab.CloseAtLimit(position, _tab.PriceBestAsk, position.OpenVolume); return; } if (position.StopOrderRedLine == 0 || position.StopOrderRedLine > priceRedLine) { _tab.CloseAtStop(position, priceRedLine, priceOrder); if (StartProgram != StartProgram.IsTester && AlertIsOn) { _alert.PriceActivation = priceRedLine - SlipageToAlert * _tab.Securiti.PriceStep; _alert.TypeActivation = PriceAlertTypeActivation.PriceHigherOrEqual; _alert.MessageIsOn = true; _alert.MusicType = AlertMusic.Duck; _alert.Message = "Приближаемся к точке выхода"; _alert.IsOn = true; } } else if (position.StopOrderIsActiv == false) { if (position.StopOrderRedLine + _tab.Securiti.PriceStep * 10 < _tab.PriceBestAsk) { _tab.CloseAtLimit(position, _tab.PriceBestAsk, position.OpenVolume); return; } position.StopOrderIsActiv = true; } } }
private void TradeLogic(List <Candle> candlesIndex, List <Candle> candlesTab) { // проверка, что робот включен делается позже, // для возможности вывода текущей фазы рынка в окно настроечных параметров // проверка на достаточность свечей if (candlesIndex.Count < _ma.Lenght + 10 || candlesIndex.Count < _bollinger.Lenght + 10 || candlesIndex.Count < _atr.Lenght + 10) { return; } // получаем последние значения инструментов и индикаторов _lastIndex = candlesIndex[candlesIndex.Count - 1].Close; _lastPrice = candlesTab[candlesTab.Count - 1].Close; _lastMa = _ma.Values[_ma.Values.Count - 1]; _lastUpBollinger = _bollinger.ValuesUp[_bollinger.ValuesUp.Count - 1]; _lastDownBollinger = _bollinger.ValuesDown[_bollinger.ValuesDown.Count - 1]; _lastAtr = _atr.Values[_atr.Values.Count - 1]; //Проверка на допустимый диапазон значений цен инструментов if (_lastPrice <= 0 || _lastIndex <= 0) { _tabSec.SetNewLogMessage("TradeLigic: цена или индекс меньше или равны нулю.", LogMessageType.Error); return; } // получаем последние значения канала индекса (спреда) GetLastChannel(); // получаем текущую фазу рынка MarketFaze currentMarketFaze = GetMarketFaze(); // если кто-то подписан на событие изменения фазы рынка, // то передаем ему текущую фазу рынка if (MarketFazeChangeEvent != null) { MarketFazeChangeEvent(currentMarketFaze); } // проверяем, что робот включен if (IsOn == false) { return; } // проверка условий закрытия позиций CheckClosingPositions(currentMarketFaze); // в зависимости от фазы рынка проверка условий открытия позиций if (currentMarketFaze == MarketFaze.Upper) { TryOpenLong(); } else if (currentMarketFaze == MarketFaze.Lower) { TryOpenShort(); } }