private void OpenPosition(PositionDirection direction, DataSample sample, string ticker, decimal amount) { Position = new Position { OpenPrice = sample.Candle.Close, Direction = direction, OpenTimestamp = sample.Candle.Timestamp, Ticker = ticker, Amount = amount }; this.OnOpenPosition(Position); }
public SignalResult SellSignal(IList <DataSample> samples, DataSample sample, Position position) { var localMinimums = ExtremumArea.FindLocalMinimums(samples); var localMaximums = ExtremumArea.FindLocalMaximums(samples); localMinimums = ExtremumArea.FillMinimumsArea(localMinimums, localMaximums); localMaximums = ExtremumArea.FillMaximumsArea(localMaximums, localMinimums); // Проверяем, не сработал ли кастомный стоплосс с учетом максимального процента потерь if (position != null) { var lastExtremumForPrice = ExtremumArea.GetLastExtremumForPriceBeforeSample(localMinimums, sample, position.OpenPrice, PositionDirection.Long); if (lastExtremumForPrice != null) { var stopLossExtremumPrice = lastExtremumForPrice.CurrentExtremum.Candle.Close; if (sample.Candle.Close < stopLossExtremumPrice - stopLossExtremumPrice * (MaxLoosePercentage / 100)) { //Console.WriteLine($"##Sell Signal triggered because sample.Candle.Close({sample.Candle.Close}) < stopLossExtremumPrice({stopLossExtremumPrice}) - stopLossExtremumPrice({stopLossExtremumPrice}) * (MaxLoosePercentage({MaxLoosePercentage}) / 100)"); return(new SignalResult() { SignalTriggered = true, ByStopLoss = true }); } } } var lastLocalMinimumPassed = false; var lastLocalMaximumPassed = false; var lastMaximumBeforeSample = ExtremumArea.GetLastMaximumBeforeAndWithSample(localMaximums, sample); var lastMinimumBeforeSample = ExtremumArea.GetLastMinimumBeforeAndWithSample(localMinimums, sample); if (lastMaximumBeforeSample != null && lastMinimumBeforeSample != null) { lastLocalMaximumPassed = lastMinimumBeforeSample.CurrentExtremum.Candle.Timestamp > lastMaximumBeforeSample.CurrentExtremum.Candle.Timestamp; //lastLocalMinimumPassed = sample.Candle.Close < lastMinimumBeforeSample.CurrentExtremum.Candle.Low; lastLocalMinimumPassed = sample.Candle.Close < lastMinimumBeforeSample.CurrentExtremum.Candle.Low; } //if (lastLocalMaximumPassed && lastLocalMinimumPassed) //Console.WriteLine($"##Sell Signal (stoploss) triggered for sample.Candle.Timestamp({sample.Candle.Timestamp}) because lastLocalMaximumPassed(minimum.Low is {lastMaximumBeforeSample.CurrentExtremum.Candle.High} maximum high is {lastMinimumBeforeSample.CurrentExtremum.Candle.Low}) and lastLocalMinimumPassed(sample.Candle.Close({sample.Candle.Close}) < lastMinimumBeforeSample.CurrentExtremum.Candle.Close({lastMinimumBeforeSample.CurrentExtremum.Candle.Close}))"); return(new SignalResult() { ByStopLoss = false, SignalTriggered = lastLocalMaximumPassed && lastLocalMinimumPassed }); }
public SignalResult SellSignal(IList <DataSample> samples, DataSample sample, Position position) { // Проверяем, не сработал ли кастомный стоплосс с учетом максимального процента потерь if (position != null && sample.Candle.Close < position.OpenPrice - position.OpenPrice * (MaxLoosePercentage / 100)) { return(new SignalResult() { SignalTriggered = true, ByStopLoss = true }); } // Если MFI выходит из зоны перепроданности var mfiCheckPassed = false; var currentSampleIndex = samples.IndexOf(sample); if (currentSampleIndex != 0) // Будем сверяться с предыдущим сэмплом. Для самого первого сверять не с чем, поэтому нужна такая проверка { // Проверяем, что MFI пересек 80ку if (((MFIIndicator)samples[currentSampleIndex - 1].Indicators["mfi"]).MFI > 80 && ((MFIIndicator)sample.Indicators["mfi"]).MFI < 80) { mfiCheckPassed = true; } } // Дополнительно проверяем, что MACD гистограмма ниже, чем на прошлом сэмпле var macdCheckPassed = false; if (currentSampleIndex != 0 ) // Будем сверяться с предыдущим сэмплом. Для самого первого сверять не с чем, поэтому нужна такая проверка { if (((MACDIndicator)samples[currentSampleIndex].Indicators["macd"]).Histogram < ((MACDIndicator)samples[currentSampleIndex - 1].Indicators["macd"]).Histogram) { macdCheckPassed = true; } } return(new SignalResult() { SignalTriggered = mfiCheckPassed && macdCheckPassed, ByStopLoss = false }); }
public decimal GetStopLossPrice(IList <DataSample> samples, DataSample sample, Position position) { var maximums = ExtremumArea.FindLocalMaximums(samples); var minimums = ExtremumArea.FindLocalMinimums(samples); ExtremumArea lastExtremum; decimal stopLossPrice = 0; if (position.Direction == PositionDirection.Long) { lastExtremum = ExtremumArea.GetLastMinimumBeforeAndWithSample(minimums, sample); stopLossPrice = lastExtremum.CurrentExtremum.Candle.Low - (position.OpenPrice - lastExtremum.CurrentExtremum.Candle.Low) * 10; //TODO убрать хардкод } else if (position.Direction == PositionDirection.Short) { lastExtremum = ExtremumArea.GetLastMaximumBeforeAndWithSample(maximums, sample); stopLossPrice = lastExtremum.CurrentExtremum.Candle.High + (lastExtremum.CurrentExtremum.Candle.High - position.OpenPrice) * 10; //TODO убрать хардкод } return(stopLossPrice); }
private double Calculate(IList <DataSample> samples, DataSample sample) { var result = 0d; double p1 = Period + 1; double EMAMultiplier = Convert.ToDouble(2 / p1); var indexOfCandle = samples.IndexOf(sample); if (indexOfCandle >= Period - 1) { EMA lastEMA = null; switch (Kind) { case EMAKind.Short: lastEMA = samples[indexOfCandle - 1].EMAshort; break; case EMAKind.Long: lastEMA = samples[indexOfCandle - 1].EMAlong; break; case EMAKind.Smoothing: lastEMA = ((MACDIndicator)samples[indexOfCandle - 1].Indicators["macd"]).EMAForMACD; break; } if (indexOfCandle == Period - 1) { // This is our seed EMA, using SMA of EMA1 Period for EMA 1 result = samples.Where(a => a.Candle.Timestamp <= sample.Candle.Timestamp).OrderByDescending(a => a.Candle.Timestamp) .Take(Period).Average(a => Convert.ToDouble(a.Candle.Close)); } else { result = (Convert.ToDouble(sample.Candle.Close) - lastEMA.Value) * EMAMultiplier + lastEMA.Value; } } return(result); }
public static ExtremumArea GetLastExtremumForPriceBeforeSample(IList <ExtremumArea> extremums, DataSample sample, decimal price, PositionDirection direction) { return(extremums.LastOrDefault(m => m.CurrentExtremum.Candle.Timestamp < sample.Candle.Timestamp && direction == PositionDirection.Long ? m.CurrentExtremum.Candle.High < price : m.CurrentExtremum.Candle.Low < price)); }
public static ExtremumArea GetLastMaximumBeforeAndWithSample(IList <ExtremumArea> extremums, DataSample sample) { return(extremums.LastOrDefault(m => m.CurrentExtremum.Candle.Timestamp <= sample.Candle.Timestamp)); }
/// <summary> /// Экспоненциальная скользящая средняя /// </summary> /// <param name="period">Период</param> /// <param name="candles">Набор свечей для расчета</param> /// <param name="candle">Свеча, для которой рассчитываем EMA</param> /// <param name="seedEMA">Флаг, указывающий, что высчитываем первоначальный EMA</param> /// <param name="kind">Тип EMA</param> public EMA(int period, IList <DataSample> samples, DataSample sample, EMAKind kind) { Period = period; Kind = kind; Value = Calculate(samples, sample); }
public MFIIndicator(DataSample sample, IList <DataSample> samples, int mfiPeriod) { Sample = sample; Samples = samples; MFIPeriod = mfiPeriod; }