示例#1
0
        /// <summary>
        /// Содержит главную логику робота по анализу свечей и принятия решений о заключении сделок. Этот метод открытый, потому что он используется при
        /// тестировании робота.
        /// </summary>
        public void CandlesAnalysisAndTrade(CandleData candle, bool isHistoryStartOff)
        {
            if (virtualDeal != null)
            {
                var virtDealResult = DalSpot.Instance.GetPointsValue(ticker, virtualDeal.Side * (candle.close - virtualDeal.PriceEnter));
                virtualResults.DequeueLast();
                virtualResults.Add(virtDealResult);
            }

            var currentSign = Math.Sign(queueFast.Average() - queueSlow.Average()); // Вычисляем текущее расположение скользящих средних

            try
            {
                if (prevSign == 0 || prevSign == currentSign)
                {
                    return;
                }
                // СС пересеклись
                // Считаем средней результат виртуальных сделок
                var avgVirtualResult = virtualResults.Length == 0 ? 0 : virtualResults.Average();

                // Если следний редультат виртуальных сделок не входит в диапазон "не торговать", то высчитываем знак текущей сделки
                maDifSign = Math.Abs(avgVirtualResult) < unknownUnitProfit ? 0 : Math.Sign(avgVirtualResult);

                // "На будущее" запоминаем текущую стуацию, для расчёта виртуальных сделок на следующих итерациях
                virtualDeal = new MarketOrder
                {
                    PriceEnter = candle.close,
                    Side       = currentSign
                };
                virtualResults.Add(0); // тут будет результат новой сделки на следующей итерации

                // пересечение скользящих средних произошло не на истории
                if (!isHistoryStartOff)
                {
                    List <MarketOrder> orders;
                    robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders);
                    var tradeSide = deriveSiteFromHistory ? currentSign * maDifSign : currentSign;
                    Trade(candle, orders, tradeSide);
                }
            }
            finally
            {
                prevSign = currentSign;

                if (debugAction != null)
                {
                    debugAction(new RobotMAInnerState
                    {
                        maDifSign   = maDifSign,
                        maValueFast = queueFast.Average(),
                        maValueSlow = queueSlow.Average(),
                        lastCandle  = candle,
                    },
                                candle.timeClose);
                }
            }
        }
示例#2
0
        public void BuildSeries(ChartControl chart)
        {
            tooltipSeries.data.Clear();
            averageRangeList.Clear();

            var candles        = chart.StockSeries.Data.Candles;
            var minimumCandles = PointsRange > 0 ? 5 : MaPeriod + 5;

            if (candles == null || candles.Count < minimumCandles)
            {
                return;
            }

            var   lastRanges = new RestrictedQueue <float>(MaPeriod);
            float targetSize = PointsRange > 0 ? DalSpot.Instance.GetAbsValue(chart.Symbol, (float)PointsRange) : 0;

            var series = 0;

            for (var i = 0; i < candles.Count; i++)
            {
                var candle = candles[i];
                var range  = candle.high - candle.low;
                lastRanges.Add(range);
                if (lastRanges.Length < lastRanges.MaxQueueLength && PointsRange == 0)
                {
                    averageRangeList.Add(0);
                    continue;
                }
                var avgRange = lastRanges.Average();
                averageRangeList.Add(avgRange);

                var candlePercent = range * 100 / avgRange;
                var isNarrow      = PointsRange > 0 ? range < targetSize
                    : candlePercent <= NarrowPercent;

                if (!isNarrow && series > 0)
                {
                    if (series >= CandlesToSignal)
                    {
                        // отметить, сколько процентов данная свеча составила от обычной волатильности
                        AddMark($"{candlePercent:F0}%", $"{candlePercent:F0}%", i, candle.open, false);
                    }
                    series = 0;
                    continue;
                }

                if (!isNarrow)
                {
                    continue;
                }

                series++;
                if (series >= CandlesToSignal)
                {
                    AddMark($"{series}", $"{series}", i, candle.close, true);
                }
            }
        }
        private void BuildIndi(Series.Series source)
        {
            if (source is IPriceQuerySeries == false)
            {
                return;
            }

            var curIndex  = 0;
            var prevAccel = 0f;

            for (var j = 0; j < source.DataCount; j++)
            {
                var medianPrice = source is CandlestickSeries
                        ? (((CandlestickSeries)source).Data.Candles[j].high +
                           ((CandlestickSeries)source).Data.Candles[j].low) * 0.5f
                        : (((IPriceQuerySeries)source).GetPrice(j) ?? 0);

                queueFast.Add(medianPrice);
                queueSlow.Add(medianPrice);

                // Если нечего рисовать то пропускаем
                var accelerator = 0f;

                /* А
                 * добил график пустыми столбиками в начале, чтобы крайний столбик был там же, где крайняя свечка
                 */
                if (queueSlow.Length >= periodSlow)
                {
                    var maSlow = queueSlow.Average();
                    var maFast = queueFast.Average();

                    //AO = SMA (MEDIAN PRICE, 5) — SMA (MEDIAN PRICE, 34)
                    var awesome = maFast - maSlow;
                    queueAwesomes.Add(awesome);

                    // Собственно значение ускорения/замедления
                    // AC = AO — SMA (AO, 5)
                    if (queueAwesomes.Length == periodAwesome)
                    {
                        accelerator = awesome - queueAwesomes.Average();
                    }
                }
                //? Класс HistogramBar не описал но вроде он не хитрый и понятно по примеру как его юзать. Для документации достаточно описаь поля и предназначение имхо

                /* А
                 * я чуть иначе раскрасил акселератор, канонически
                 */
                seriesDeltas.data.Add(new HistogramBar
                {
                    color = accelerator >= prevAccel ? ClBarsPositive : ClBarsNegative,
                    index = curIndex++,
                    y     = accelerator
                });
                prevAccel = accelerator;
            }
        }
示例#4
0
 private float CalculateBrickSize()
 {
     if (lastPrices.Length < AutosizePeriod)
     {
         return(pointCost * brickSize);
     }
     if (VolatilityType == RencoVolatilityType.азмах)
     {
         return((lastPrices.Max(c => c.high) - lastPrices.Min(c => c.low)) * AutosizeScale);
     }
     //if (VolatilityType == RencoVolatilityType.ATR)
     return(lastPrices.Average(p => p.high - p.low) * AutosizeScale);
 }
示例#5
0
        private static double [] ReduceTrendMA(double [] data, int maPeriod)
        {
            var maData  = new RestrictedQueue <double>(maPeriod);
            var outData = new List <double>();

            for (var i = 0; i < data.Length; i++)
            {
                maData.Add(data[i]);
                if (maData.Length < maPeriod)
                {
                    continue;
                }
                var ma = maData.Average();
                outData.Add(data[i] / ma);
            }
            return(outData.ToArray());
        }
示例#6
0
        // ReSharper disable InconsistentNaming
        private void BuildMA(Series.Series source)
        // ReSharper restore InconsistentNaming
        {
            series.Data.Clear();
            float sum      = 0;
            var   frameLen = 0;

            for (var i = 0; i < source.DataCount; i++)
            {
                var price = GetPrice(source, i);

                // простая СС
                if (maType == MovAvgType.Простая)
                {
                    sum += price;
                    if (frameLen < period)
                    {
                        frameLen++;
                    }
                    else
                    {
                        sum -= GetPrice(source, i - period);
                    }
                    series.Data.Add(sum / frameLen);
                    continue;
                }

                // сглаженная СС
                if (smmaPrev.HasValue)
                {
                    var smma = ((period - 1) * smmaPrev.Value + price) / period;
                    series.Data.Add(smma);
                    smmaPrev = smma;
                }
                else
                {
                    queue.Add(price);
                    if (queue.Length == period)
                    {
                        smmaPrev = queue.Average();
                    }
                    series.Data.Add(smmaPrev ?? price);
                }
            }
        }
示例#7
0
        private void BuildIndi(Series source)
        {
            if (source is CandlestickSeries == false)
            {
                return;
            }
            var candles = ((CandlestickSeries)source).Data.Candles;

            var currentSign = 0; // текущая операция (покупка/продажа)
            var curIndex    = 0;

            foreach (var candle in candles)
            {
                var price = candle.GetPrice(priceType);
                // обновить средние
                queueFast.Add(price);
                queueSlow.Add(price);

                // посчитать профит
                var delta = 0f;
                if (currentSign != 0)
                {
                    delta = (candle.close - candle.open) * currentSign;
                }
                seriesDeltas.data.Add(new HistogramBar
                {
                    color = delta >= 0 ? ClBarsPositive : ClBarsNegative,
                    index = curIndex++,
                    y     = delta
                });
                // определить знак
                if (queueSlow.Length < periodSlow)
                {
                    continue;
                }
                var maSlow  = queueSlow.Average();
                var maFast  = queueFast.Average();
                var newSign = maFast > maSlow ? 1 : maFast < maSlow ? -1 : 0;
                if (newSign != 0)
                {
                    currentSign = newSign;
                }
            }
        }
        public void BuildSeries(ChartControl chart)
        {
            tooltipSeries.data.Clear();
            averageRangeList.Clear();
            seriesUp.Data.Clear();
            seriesDn.Data.Clear();

            var candles        = chart.StockSeries.Data.Candles;
            var minimumCandles = PointsRange > 0 ? 5 : MaPeriod + 5;

            if (candles == null || candles.Count < minimumCandles)
            {
                return;
            }

            var   lastRanges = new RestrictedQueue <float>(MaPeriod);
            var   lastHL     = new RestrictedQueue <float>(MaPeriod);
            float targetSize = PointsRange > 0 ? DalSpot.Instance.GetAbsValue(chart.Symbol, (float)PointsRange) : 0;

            var curFrame = candles.Take(FrameLength).ToList();

            lastRanges.Add(curFrame.Max(c => c.high) - curFrame.Min(c => c.low));

            seriesUp.Data.Add(candles[0].high);
            seriesDn.Data.Add(candles[0].low);
            for (var i = 0; i < FrameLength; i++)
            {
                averageRangeList.Add(0);
                seriesUp.Data.Add(candles[i].high);
                seriesDn.Data.Add(candles[i].low);
            }
            var breakCandleLengthPercents = new List <float>();
            var prevFrameIsNarrow         = false;

            for (var i = FrameLength; i < candles.Count; i++)
            {
                var candle = candles[i];
                curFrame.RemoveAt(0);
                curFrame.Add(candle);

                var high = curFrame[0].high;
                var low  = curFrame[0].low;
                foreach (var c in curFrame.Skip(1))
                {
                    if (c.high > high)
                    {
                        high = c.high;
                    }
                    if (c.low < low)
                    {
                        low = c.low;
                    }
                }
                var range = high - low;
                lastRanges.Add(range);
                lastHL.Add(candle.high - candle.low);

                if (lastRanges.Length < lastRanges.MaxQueueLength && PointsRange == 0)
                {
                    averageRangeList.Add(0);
                    seriesUp.Data.Add(candles[i].high);
                    seriesDn.Data.Add(candles[i].low);
                    continue;
                }
                var avgRange = lastRanges.Average();
                averageRangeList.Add(avgRange);
                seriesUp.Data.Add(candles[i].close + range);
                seriesDn.Data.Add(candles[i].close - range);

                var avgHl        = lastHL.Average();
                var rangePercent = avgRange == 0 ? 0 : range * 100 / avgRange;
                var isNarrow     = PointsRange > 0 ? range < targetSize
                    : rangePercent <= NarrowPercent;

                if (prevFrameIsNarrow) // && !isNarrow)
                {
                    // отметить, сколько процентов данная свеча составила от обычной волатильности
                    var candlePercent = avgHl == 0 ? 0 : (candle.high - candle.low) * 100 / avgHl;
                    if (candlePercent > 0)
                    {
                        breakCandleLengthPercents.Add(candlePercent);
                    }
                    AddMark($"{candlePercent:F0}%", $"{candlePercent:F0}%", i, candle.open, false);
                }
                prevFrameIsNarrow = isNarrow;
            }

            // вывести в лог среднее
            if (breakCandleLengthPercents.Count > 0)
            {
                avgBreakCandle = breakCandleLengthPercents.Average();
                minBreakCandle = breakCandleLengthPercents.Min();
                maxBreakCandle = breakCandleLengthPercents.Max();
                breaksCount    = breakCandleLengthPercents.Count;
                Logger.Info($"{breakCandleLengthPercents.Count}, от {minBreakCandle:F1} до {maxBreakCandle:F1}, среднее: {avgBreakCandle:F1}");
            }
        }
示例#9
0
 private static double[] ReduceTrendMA(double []data, int maPeriod)
 {
     var maData = new RestrictedQueue<double>(maPeriod);
     var outData = new List<double>();
     for (var i = 0; i < data.Length; i++)
     {
         maData.Add(data[i]);
         if (maData.Length < maPeriod) continue;
         var ma = maData.Average();
         outData.Add(data[i] / ma);
     }
     return outData.ToArray();
 }
示例#10
0
        public void BuildSeries(ChartControl chart)
        {
            seriesK.Data.Clear();
            seriesD.Data.Clear();
            seriesBounds.parts.Clear();

            if (SeriesSources.Count == 0)
            {
                return;
            }
            var source = SeriesSources[0];

            if (source.DataCount == 0)
            {
                return;
            }

            if (source is CandlestickSeries == false &&
                source is LineSeries == false)
            {
                return;
            }

            // границы
            if (lowerBound > 0)
            {
                seriesBounds.parts.Add(new List <PartSeriesPoint>
                {
                    new PartSeriesPoint(1, lowerBound),
                    new PartSeriesPoint(source.DataCount, lowerBound)
                });
            }
            if (upperBound > 0 && upperBound < 100)
            {
                seriesBounds.parts.Add(new List <PartSeriesPoint>
                {
                    new PartSeriesPoint(1, upperBound),
                    new PartSeriesPoint(source.DataCount, upperBound)
                });
            }

            queue   = new RestrictedQueue <float>(period);
            queueMA = new RestrictedQueue <float>(periodMA);

            for (var i = 0; i < source.DataCount; i++)
            {
                var price =
                    source is CandlestickSeries
                        ? ((CandlestickSeries)source).Data.Candles[i].close
                        : ((LineSeries)source).GetPrice(i) ?? 0;
                queue.Add(price);

                if (queue.Length < period)
                {
                    seriesK.Data.Add(50);
                    seriesD.Data.Add(50);
                    continue;
                }
                var minValue = float.MaxValue;
                var maxValue = float.MinValue;
                foreach (var p in queue)
                {
                    if (p < minValue)
                    {
                        minValue = p;
                    }
                    if (p > maxValue)
                    {
                        maxValue = p;
                    }
                }
                var range = maxValue - minValue;
                var k     = range == 0 ? 50 : 100 * (price - minValue) / range;
                queueMA.Add(k);
                var d = queueMA.Length == periodMA?queueMA.Average() : k;

                seriesK.Data.Add(k);
                seriesD.Data.Add(d);
            }
        }
示例#11
0
        private void BuildBollinger(Series.Series source)
        {
            series.Data.Clear();
            seriesUp.Data.Clear();
            seriesDn.Data.Clear();
            if (source is CandlestickSeries == false &&
                source is LineSeries == false)
            {
                return;
            }

            float sum      = 0;
            var   frameLen = 0;

            for (var i = 0; i < source.DataCount; i++)
            {
                var price = GetPrice(source, i);

                // простая СС
                if (MaType == MovAvgType.Простая)
                {
                    sum += price;
                    if (frameLen < period)
                    {
                        frameLen++;
                    }
                    else
                    {
                        sum -= GetPrice(source, i - period);
                    }
                    series.Data.Add(sum / frameLen);
                }

                // сглаженная СС
                else
                {
                    if (smmaPrev.HasValue)
                    {
                        var smma = ((period - 1) * smmaPrev.Value + price) / period;
                        series.Data.Add(smma);
                        smmaPrev = smma;
                    }
                    else
                    {
                        queue.Add(price);
                        if (queue.Length == period)
                        {
                            smmaPrev = queue.Average();
                        }

                        series.Data.Add(smmaPrev ?? price);
                    }
                }

                // волатильность (СКО)
                // очередь из квадратов отклонений
                var lastMedian = series.Data[series.Data.Count - 1];
                var dev        = lastMedian - price;
                queueDisper.Add((float)(dev * dev));

                var ssd = queueDisper.Length == period
                              ? Math.Sqrt(queueDisper.Average())
                              : 0;

                seriesUp.Data.Add(lastMedian + KVolatile * ssd);
                seriesDn.Data.Add(lastMedian - KVolatile * ssd);
            }
        }
        private void PlaceMarkers()
        {
            var candles = chart.chart.StockSeries.Data.Candles;

            if (candles.Count <= FrameLength + MaPeriod)
            {
                return;
            }

            var lastRanges = new RestrictedQueue <float>(MaPeriod);

            var curFrame = candles.Take(FrameLength).ToList();

            lastRanges.Add(curFrame.Max(c => c.high));

            var prevFrameIsNarrow = false;

            for (var i = FrameLength; i < candles.Count; i++)
            {
                var candle = candles[i];
                curFrame.RemoveAt(0);
                curFrame.Add(candle);

                var high = curFrame[0].high;
                var low  = curFrame[0].low;
                foreach (var c in curFrame.Skip(1))
                {
                    if (c.high > high)
                    {
                        high = c.high;
                    }
                    if (c.low < low)
                    {
                        low = c.low;
                    }
                }
                var range = high - low;
                lastRanges.Add(range);

                if (lastRanges.Length < lastRanges.MaxQueueLength)
                {
                    continue;
                }
                var avgRange = lastRanges.Average();

                var rangePercent = avgRange == 0 ? 0 : range * 100 / avgRange;
                var isNarrow     = rangePercent <= NarrowPercent;

                if (prevFrameIsNarrow) // && !isNarrow)
                {
                    if (i <= MomentumPeriod)
                    {
                        continue;
                    }
                    var prevClose = candles[i - MomentumPeriod - 1].close;
                    if (prevClose <= 0)
                    {
                        continue;
                    }
                    var momentum = candles[i - 1].close * 100 / prevClose;
                    var side     = momentum > 100 ? -1 : 1;

                    AddMark(side, i, candles, $"M: {momentum:F1}");
                }
                prevFrameIsNarrow = isNarrow;
            }
        }
示例#13
0
        public void BuildSeries(ChartControl chart)
        {
            seriesK.Data.Clear();
            seriesD.Data.Clear();
            seriesBounds.parts.Clear();

            if (SeriesSources.Count == 0) return;
            var source = SeriesSources[0];
            if (source.DataCount == 0) return;

            if (source is CandlestickSeries == false &&
                source is LineSeries == false) return;

            // границы
            if (lowerBound > 0)
                seriesBounds.parts.Add(new List<PartSeriesPoint>
                                       {
                                           new PartSeriesPoint(1, lowerBound),
                                           new PartSeriesPoint(source.DataCount, lowerBound)
                                       });
            if (upperBound > 0 && upperBound < 100)
            seriesBounds.parts.Add(new List<PartSeriesPoint>
                                       {
                                           new PartSeriesPoint(1, upperBound),
                                           new PartSeriesPoint(source.DataCount, upperBound)
                                       });

            queue = new RestrictedQueue<float>(period);
            queueMA = new RestrictedQueue<float>(periodMA);

            for (var i = 0; i < source.DataCount; i++)
            {
                var price =
                    source is CandlestickSeries
                        ? ((CandlestickSeries) source).Data.Candles[i].close
                        : ((LineSeries) source).GetPrice(i) ?? 0;
                queue.Add(price);

                if (queue.Length < period)
                {
                    seriesK.Data.Add(50);
                    seriesD.Data.Add(50);
                    continue;
                }
                var minValue = float.MaxValue;
                var maxValue = float.MinValue;
                foreach (var p in queue)
                {
                    if (p < minValue) minValue = p;
                    if (p > maxValue) maxValue = p;
                }
                var range = maxValue - minValue;
                var k = range == 0 ? 50 : 100*(price - minValue)/range;
                queueMA.Add(k);
                var d = queueMA.Length == periodMA ? queueMA.Average() : k;

                seriesK.Data.Add(k);
                seriesD.Data.Add(d);
            }
        }