Пример #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);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Прорисовка кнопки на элементе "Graphics" контрола "QuoteTradeControl"
        /// </summary>
        /// <param name="graphics">Объект, на котором будт осущесвлятся прорисовка</param>
        public void Draw(Graphics graphics)
        {
            scaleMatrix = new Matrix();
            scaleMatrix.Scale(ScaleX, ScaleY);
            Shape = QuotePartButtonFigure.instanceFigure.Clone() as GraphicsPath;
            Shape.Transform(translateMatrix);
            Shape.Transform(scaleMatrix);

            graphics.FillPath(currentBrush, Shape);
            graphics.DrawPath(pensStor.GetPen(Color.FromArgb(255, 64, 66, 64)), Shape);

            if (buySellIndicator != null)
            {
                if (Value != null)
                {
                    // Запоминаем значение для вычсления направления стрелки тренда
                    if (buySellIndicator.Volume == Value)
                    {
                        trandDeltaValues.Add(0);
                    }
                    else
                    {
                        trandDeltaValues.Add(buySellIndicator.Volume > Value ? -1 : 1);
                    }

                    buySellIndicator.Volume = Value;
                }

                buySellIndicator.ScaleX = ScaleX;
                buySellIndicator.ScaleY = ScaleY;

                buySellIndicator.Draw(graphics, brushesStor);
            }

            if (arrowTrend != null)
            {
                arrowTrend.Sx = ScaleX;
                arrowTrend.Sy = ScaleY;


                arrowTrend.DirectionAngle = trandDeltaValues.GetItemByIndex(0, true) * 1 + trandDeltaValues.GetItemByIndex(1, true) * 2 + trandDeltaValues.GetItemByIndex(2, true) * 4;

                arrowTrend.Draw(graphics);
            }
        }
Пример #4
0
        /// <summary>
        /// Этот метод вызывается каждый раз при новых данных котировки. Метод реализует основную логику торговли робота.
        /// Здесь принимается решение о открытии нового ордера и закрытии открытых сделок
        /// Совершение сделок будет поисходить на закрытии свечи. При закрытии свечки метод  UpdateCandle объекта packer вернёт эту свечу, иначе Null.
        /// В случае если свеча закрылась, тогда методом CalculateMA расчитываем значение скользящей средней для текущей котировки.
        /// Если быстрая и медленная скользящие седние пересекаются, а так же если текущая котировка не является "исторической", тогда можно
        /// принимать решение об открытии новой сделки.
        /// </summary>
        /// <param name="quotes"></param>
        /// <param name="isHistoryStartOff">Флаг, показывающий, является текущая котировка взятой из истории, или это значение катировки на текущий момент на рынке</param>
        /// <param name="names"></param>
        public override List <string> OnQuotesReceived(string[] names,
                                                       CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            events = lastMessages.ToList();
            lastMessages.Clear();

            #region Получение текущей свечи
            // Массивы "names" и "quotes" всегда содержат одинаковое количество элементов (по одному). Фактически это пары ключ/значение

            if (string.IsNullOrEmpty(ticker))
            {
                var accountId = 0;
                if (robotContext != null && robotContext.AccountInfo != null)
                {
                    accountId = robotContext.AccountInfo.ID;
                }
                Logger.ErrorFormat("Название текущего инструмента ({0}) для робота \"{1}\" (#{2}) задано не корректно",
                                   ticker ?? "", TypeName, accountId);
                return(events);
            }
            var tickerIndex = -1;
            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] == ticker)
                {
                    tickerIndex = i;
                    break;
                }
            }
            if (tickerIndex < 0)
            {
                //Logger.InfoFormat("Не удалось получить котировку для робота {0}", TypeName);
                return(events);
            }

            //Выбираем из всего массива текущих катировкок, катировку для того инструмента, которым торгует робот
            var quote = quotes[tickerIndex];


            var candle = packer.UpdateCandle(quote);
            #endregion

            // Если свеча закрылась, тогда candle != null  (сделки соверши)
            if (candle == null)
            {
                return(events);
            }

            queueSlow.Add(candle.close);
            queueFast.Add(candle.close);
            if (queueSlow.Length < queueSlow.MaxQueueLength)
            {
                return(events);
            }
            CandlesAnalysisAndTrade(candle, isHistoryStartOff);
            return(events);
        }
        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;
            }
        }
Пример #6
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            var events = new List <string>();
            var candle = UpdateCurrentCandle(names, quotes);

            if (candle == null)
            {
                return(events);
            }

            // проверить Каймана
            CandleData cayCandle;

            if (!caymanCandles.TryGetValue(candle.timeOpen, out cayCandle))
            {
                return(events);
            }

            // знак Каймана
            var sign = cayCandle.close >= 50 ? -1 : 1;

            caymanLastSigns.Add(sign);
            if (caymanLastSigns.Length < caymanLastSigns.MaxQueueLength)
            {
                return(events);
            }

            // последняя сделка
            List <MarketOrder> orders;

            GetMarketOrders(out orders);
            var lastOrder = orders.LastOrDefault();

            // закрыть ордер
            if (lastOrder != null && sign != lastOrder.Side)
            {
                CloseMarketOrder(lastOrder.ID);
                lastOrder = null;
            }

            // войти в рынок?
            if (lastOrder != null)
            {
                return(events);
            }
            if (caymanLastSigns.Any(s => s != sign))
            {
                return(events);
            }
            OpenDeal(candle.close, sign);

            return(events);
        }
Пример #7
0
        private int GetRencoSignal(CandleData candle)
        {
            var brickSizeAbs = brickSize * pointCost;

            // автомасштаб...
            if (BrickSizeAuto)
            {
                lastPrices.Add(candle);
                brickSizeAbs = CalculateBrickSize();
            }

            // проверить - добавлен ли новый кирпич? сменился ли знак кирпича?
            if (lastBrick == null)
            {
                var brickDir = candle.close < candle.open ? -1 : 1;
                lastBrick = new RencoRobotBrick(candle.open, candle.close, brickDir);
                return(0);
            }

            var deltaClose = (int)((candle.close - lastBrick.priceClose) / brickSizeAbs);
            var deltaOpen  = (int)((candle.close - lastBrick.priceOpen) / brickSizeAbs);

            if (deltaClose > 0 && lastBrick.direction > 0)
            {
                lastBrick = new RencoRobotBrick(
                    lastBrick.priceClose + (deltaClose - 1) * brickSizeAbs,
                    lastBrick.priceClose + deltaClose * brickSizeAbs, 1);
                return(0);
            }
            if (deltaOpen < 0 && lastBrick.direction > 0)
            {
                lastBrick = new RencoRobotBrick(
                    lastBrick.priceOpen + (deltaOpen + 1) * brickSizeAbs,
                    lastBrick.priceOpen + deltaOpen * brickSizeAbs, -1);
                return(-1);
            }
            if (deltaClose < 0 && lastBrick.direction < 0)
            {
                lastBrick = new RencoRobotBrick(
                    lastBrick.priceClose + (deltaClose + 1) * brickSizeAbs,
                    lastBrick.priceClose + deltaClose * brickSizeAbs, -1);
                return(0);
            }
            if (deltaOpen > 0 && lastBrick.direction < 0)
            {
                lastBrick = new RencoRobotBrick(
                    lastBrick.priceOpen + (deltaOpen - 1) * brickSizeAbs,
                    lastBrick.priceOpen + deltaOpen * brickSizeAbs, 1);
                return(1);
            }
            return(0);
        }
Пример #8
0
        /// <summary>
        /// Проверяет, является ли средний элемент в "queue" локальным экстремумом
        /// </summary>
        private void CheckExtremum(RestrictedQueue <CandleData> queue)
        {
            bool isMax = true, isMin = true;

            // Проверяемая на экстремум свеча
            var checkingCandle = queue.ElementAt(ExtremumRange);

            for (var i = 0; i < queue.MaxQueueLength; i++)
            {
                if (i == ExtremumRange)
                {
                    continue;
                }
                var candle = queue.ElementAt(i);
                if (checkingCandle.close <= candle.close)
                {
                    isMax = false;
                }
                if (checkingCandle.close >= candle.close)
                {
                    isMin = false;
                }
                if (!isMax && !isMin)
                {
                    return;
                }
            }

            if (isMax)
            {
                extremumQueue.Add(new Cortege3 <float, bool, DateTime>(checkingCandle.close, true, checkingCandle.timeClose));
            }
            if (isMin)
            {
                extremumQueue.Add(new Cortege3 <float, bool, DateTime>(checkingCandle.close, false, checkingCandle.timeClose));
            }
        }
Пример #9
0
 public void DetermineSentimentColorIndex(float bid)
 {
     colorCurrent = colorNeutral;
     if (prevBids.Length > 0)
     {
         signCurrent = Math.Sign(bid - prevBids.Last);
         if (signCurrent != 0)
         {
             var sum   = prevBids.Sum(pBid => Math.Sign(bid - pBid));
             var index = signCurrent == Math.Sign(sum) ? Math.Abs(sum) - 1 : 0;
             colorCurrent = signCurrent > 0 ? colorsGrowth[index] : colorsFall[index];
         }
     }
     prevBids.Add(bid);
 }
Пример #10
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());
        }
Пример #11
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);
                }
            }
        }
Пример #12
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;
                }
            }
        }
Пример #13
0
        private string BuildSeries()
        {
            var indi = chart.indicators.FirstOrDefault(i => i.GetType() == typeof(IndicatorExternSeries));

            if (indi == null)
            {
                return("Нет данных для построения (данные из файла)");
            }
            var indiData = indi.SeriesResult[0] as CandlestickSeries;

            if (indiData.DataCount == 0)
            {
                return("Индикатор пуст");
            }
            var candles = chart.chart.StockSeries.Data.Candles;
            var max     = Math.Min(candles.Count, indiData.DataCount);

            var lastSign  = 0;
            var lastSigns = new RestrictedQueue <int>(skippedCandles);

            var       lines     = new List <TrendLine>();
            TrendLine trendLine = null;

            for (var i = 0; i < max; i++)
            {
                var candle      = indiData.Data[i];
                var chartCandle = candles[i];
                var thisSign    = GetCaymanSign(candle);
                lastSigns.Add(thisSign);

                // растянуть регион
                if (trendLine != null)
                {
                    trendLine.AddPoint(i, chartCandle.close);

                    if (thisSign == lastSign)
                    {
                        continue;
                    }
                }

                lastSign = thisSign;

                // завершить регион
                if (trendLine != null)
                {
                    trendLine = null;
                    continue;
                }

                if (lastSigns.Any(s => s != lastSign) || lastSigns.Length < skippedCandles)
                {
                    continue;
                }
                // новая линия
                trendLine = new TrendLine
                {
                    Comment   = CommentSpecName,
                    Magic     = LineMagic,
                    LineColor = thisSign > 0 ? colorSell : ColorBuy
                };
                trendLine.AddPoint(i, chartCandle.close);
                lines.Add(trendLine);
            }

            MakeChartGraph(lines);
            return("Построено " + lines.Count + " областей");
        }
Пример #14
0
        public override List <string> OnQuotesReceived(string[] names, QuoteData[] quotes, bool isHistoryStartOff)
        {
            if (formulaResolver == null || packer == null)
            {
                return(null);
            }
            curTime = quotes[0].time;

            // обновить табличку цен
            for (var i = 0; i < names.Length; i++)
            {
                if (lastBids.ContainsKey(names[i]))
                {
                    lastBids[names[i]] = quotes[i].bid;
                }
                else
                {
                    lastBids.Add(names[i], quotes[i].bid);
                }
            }

            QuoteData curQuote = null;

            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] == ticker)
                {
                    curQuote = quotes[i];
                    break;
                }
            }

            if (curQuote == null)
            {
                return(null);                  // нет торгуемой котировки
            }
            // обновить свечки
            var candle = packer.UpdateCandle(curQuote.bid, curQuote.time);
            Dictionary <string, double> varValues = null;

            if (candle != null)
            {
                candles.Add(candle);
                countCandles++;
                // обновить очереди (для индекса, переменные вида usdjpy#15)
                if (lastBidLists.Count > 0)
                {
                    foreach (var listTicker in lastBidLists)
                    {
                        float price;
                        if (!lastBids.TryGetValue(listTicker.Key, out price))
                        {
                            price = 0;
                        }
                        listTicker.Value.Add(price);
                    }
                }
                // посчитать индекс
                double index;
                varValues = GetVariableValues();
                if (formulaResolver.Calculate(varValues, out index))
                {
                    lastIndexValue = double.IsNaN(index) ? 0 : (float)index;
                }
                lastIndicies.Add(lastIndexValue ?? 0);
            }

            // если это период "разгона" конвейера
            if (isHistoryStartOff)
            {
                return(null);
            }

            RobotHint hint = null;

            // получить знак дивергенции
            if (candle != null)
            {
                string             commentOnDivergence = string.Empty;
                var                divergenceSign      = GetDivergenceSign(out commentOnDivergence);
                List <MarketOrder> orders;
                robotContext.GetMarketOrders(robotContext.accountInfo.ID, out orders);
                if (divergenceSign != 0)
                {
                    var hintText = new StringBuilder();
                    hintText.AppendLine(commentOnDivergence);
                    hintText.AppendLine("Переменные:");
                    // ReSharper disable PossibleNullReferenceException)
                    foreach (var pair in varValues)
                    // ReSharper restore PossibleNullReferenceException
                    {
                        hintText.AppendLine(string.Format("{1}{0}{2:f4}", (char)9, pair.Key, pair.Value));
                    }

                    hint = new RobotHint(Graphics[0].a, Graphics[0].b.ToString(),
                                         hintText.ToString(), divergenceSign > 0 ? "BUY" : "SELL", "e", curQuote.bid)
                    {
                        Time = candle.timeOpen,
                        //curTime
                        ColorFill     = divergenceSign > 0 ? Color.Green : Color.Red,
                        ColorLine     = Color.Black,
                        RobotHintType = divergenceSign > 0
                                                       ? RobotHint.HintType.Покупка
                                                       : RobotHint.HintType.Продажа
                    };

                    // если получен сигнал на покупку - купить, закрыв продажи
                    // наоборот, если получен сигнал на продажу - продать, закрыв покупки
                    var ordersToClose = orders.FindAll(o => o.Side != divergenceSign);
                    foreach (var order in ordersToClose)
                    {
                        robotContext.SendCloseRequest(CurrentProtectedContext.Instance.MakeProtectedContext(),
                                                      robotContext.accountInfo.ID, order.ID, PositionExitReason.ClosedByRobot);
                    }

                    // открыть позу в направлении знака дивера
                    decimal?stop = StopLossPoints == 0
                                        ? (decimal?)null
                                        : (decimal)curQuote.bid -
                                   divergenceSign * DalSpot.Instance.GetAbsValue(ticker, (decimal)StopLossPoints);
                    decimal?take = TakeProfitPoints == 0
                                        ? (decimal?)null
                                        : (decimal)curQuote.bid +
                                   divergenceSign * DalSpot.Instance.GetAbsValue(ticker, (decimal)TakeProfitPoints);

                    robotContext.SendNewOrderRequest(CurrentProtectedContext.Instance.MakeProtectedContext(),
                                                     RequestUniqueId.Next(), robotContext.accountInfo.ID, Magic, ticker, Volume,
                                                     divergenceSign, OrderType.Market, 0, 0,
                                                     stop, take, null, null, string.Empty, "OscillatorBasedRobot");
                }
            }

            return(hint != null ? new List <string> {
                hint.ToString()
            } : null);
        }
Пример #15
0
        private string BuildSeries()
        {
            var indi = chart.indicators.FirstOrDefault(i => i.GetType() == typeof (IndicatorExternSeries));
            if (indi == null)
                return "Нет данных для построения (данные из файла)";
            var indiData = indi.SeriesResult[0] as CandlestickSeries;
            if (indiData.DataCount == 0) return "Индикатор пуст";
            var candles = chart.chart.StockSeries.Data.Candles;
            var max = Math.Min(candles.Count, indiData.DataCount);

            var lastSign = 0;
            var lastSigns = new RestrictedQueue<int>(skippedCandles);

            var lines = new List<TrendLine>();
            TrendLine trendLine = null;

            for (var i = 0; i < max; i++)
            {
                var candle = indiData.Data[i];
                var chartCandle = candles[i];
                var thisSign = GetCaymanSign(candle);
                lastSigns.Add(thisSign);

                // растянуть регион
                if (trendLine != null)
                {
                    trendLine.AddPoint(i, chartCandle.close);

                    if (thisSign == lastSign)
                        continue;
                }

                lastSign = thisSign;

                // завершить регион
                if (trendLine != null)
                {
                    trendLine = null;
                    continue;
                }

                if (lastSigns.Any(s => s != lastSign) || lastSigns.Length < skippedCandles) continue;
                // новая линия
                trendLine = new TrendLine
                {
                    Comment = CommentSpecName,
                    Magic = LineMagic,
                    LineColor = thisSign > 0 ? colorSell : ColorBuy
                };
                trendLine.AddPoint(i, chartCandle.close);
                lines.Add(trendLine);
            }

            MakeChartGraph(lines);
            return "Построено " + lines.Count + " областей";
        }
Пример #16
0
        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}");
            }
        }
Пример #17
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);
            }
        }
Пример #18
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();
 }
Пример #19
0
        public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff)
        {
            var events = new List <string>();

            #region получить candle из quote
            if (string.IsNullOrEmpty(ticker))
            {
                return(events);
            }
            var tickerIndex = -1;
            for (var i = 0; i < names.Length; i++)
            {
                if (names[i] == ticker)
                {
                    tickerIndex = i;
                    break;
                }
            }
            if (tickerIndex < 0)
            {
                return(events);
            }
            var quote = quotes[tickerIndex];

            var candle = packer.UpdateCandle(quote);
            if (candle == null)
            {
                return(events);
            }
            #endregion

            extremumRangeQueue.Add(candle);
            if (extremumRangeQueue.Length != extremumRangeQueue.MaxQueueLength)
            {
                return(events);
            }


            //  Если очередь заполнена полностью, значит можно проверять её среднее значение на локальный экстремум
            CheckExtremum(extremumRangeQueue);

            //  Все ли 4 экстремума сейчас имеются для анализа
            if (extremumQueue.Length != extremumQueue.MaxQueueLength)
            {
                return(events);
            }

            var extrArray = extremumQueue.ToArray();
            //  Теперь можно проверить - чередуются ли экстремумы.
            var boofSign = !extrArray[0].b;
            foreach (var extremum in extrArray)
            {
                if (extremum.b == boofSign)
                {
                    return(events); // Это значит что два максимума или два минимума идут друг за другом
                }
                boofSign = !boofSign;
            }

            //  Экстремумы чередуются друг за другом.
            //  Теперь проверяем, больше ли по модулю "а", чем "b", "с" и "d" и close.
            var priceA      = extrArray[0].a;
            var currentSide = extrArray[0].b ? 1 : -1;

            for (var i = 1; i < extrArray.Length; i++)
            {
                if (currentSide != Math.Sign(priceA - extrArray[i].a))
                {
                    return(events);
                }
            }
            if (currentSide != Math.Sign(priceA - candle.close))
            {
                return(events);
            }

            // соотнесение "плеч"
            var ab     = Math.Abs(extrArray[0].a - extrArray[1].a);
            var bc     = Math.Abs(extrArray[1].a - extrArray[2].a);
            var cd     = Math.Abs(extrArray[2].a - extrArray[3].a);
            var dClose = Math.Abs(extrArray[3].a - candle.close);

            var bcCd = cd == 0 ? float.MaxValue : bc / cd;
            if (bcCd < MinShoulder || bcCd > MaxShoulder)
            {
                return(events);
            }
            if (ab <= bc || ab <= cd || ab <= dClose)
            {
                return(events);
            }

            //  Первый экстремум является большим по модулю, чем остальные - можно совершать сделку
            if (!isHistoryStartOff) // линии скользящих средних пересеклись причём не на истории. Значит пора торговать!!!
            {
                // коментарий
                var extrNames = new [] { "A", "B", "C", "D" };
                var nameIndex = 0;
                // ReSharper disable LoopCanBeConvertedToQuery
                foreach (var extr in extrArray)
                // ReSharper restore LoopCanBeConvertedToQuery
                {
                    events.Add(new RobotHint(ticker,
                                             Graphics[0].b.ToString(),
                                             extrNames[nameIndex],
                                             extrNames[nameIndex],
                                             extrNames[nameIndex++], extr.a)
                    {
                        Time          = extr.c,
                        RobotHintType = RobotHint.HintType.Линия         //extr.b ? RobotHint.HintType.Покупка : RobotHint.HintType.Продажа
                    }.ToString());
                }

                // закрыть противонаправленные, если автозакрытие включено пользователем
                if (CloseDeal)
                {
                    List <MarketOrder> orders;
                    robotContext.GetMarketOrders(robotContext.AccountInfo.ID, out orders);
                    foreach (
                        var order in
                        orders.Where(o => o.Side != currentSide && o.Magic == Magic && o.Symbol == ticker).ToList())
                    {
                        robotContext.SendCloseRequest(protectedContext.MakeProtectedContext(),
                                                      robotContext.AccountInfo.ID, order.ID, PositionExitReason.ClosedByRobot);
                    }
                }

                OpenDeal(candle.close, currentSide);
            }
            return(events);
        }
Пример #20
0
        protected string BuildSeries()
        {
            var indi = chart.indicators.FirstOrDefault(i => i.GetType() == typeof(IndicatorExternSeries));

            if (indi == null)
            {
                return("Нет данных для построения (данные из файла)");
            }
            var indiData = indi.SeriesResult[0] as CandlestickSeries;

            if (indiData.DataCount == 0)
            {
                return("Индикатор пуст");
            }
            var candles = chart.chart.StockSeries.Data.Candles;
            var max     = Math.Min(candles.Count, indiData.DataCount);

            var       lines       = new List <TrendLine>();
            TrendLine trendLine   = null;
            var       dealSign    = 0;
            var       caymanSigns = new RestrictedQueue <int>(skippedCandles);

            for (var i = 0; i < max; i++)
            {
                var candle = indiData.Data[i];
                var chartCandle = candles[i];
                var extremumSign = candle.close <lowerMargin ? -1 : candle.close> upperMargin ? 1 : 0;
                caymanSigns.Add(extremumSign);

                if (dealSign != 0)
                {
                    trendLine.AddPoint(i, chartCandle.close);
                    if ((dealSign < 0 && candle.close > 50) ||
                        (dealSign > 0 && candle.close < 50))
                    {
                        trendLine = null;
                        dealSign  = 0;
                    }
                    continue;
                }

                dealSign = caymanSigns.Last;
                if (dealSign == 0)
                {
                    continue;
                }
                if (caymanSigns.Any(s => s != dealSign))
                {
                    dealSign = 0;
                    continue;
                }

                trendLine = new TrendLine
                {
                    Comment   = CommentSpecName,
                    Magic     = LineMagic,
                    LineColor = dealSign > 0 ? colorSell : ColorBuy
                };
                trendLine.AddPoint(i, chartCandle.close);
                trendLine.AddPoint(i, chartCandle.close);
                lines.Add(trendLine);
            }

            MakeChartGraph(lines);
            return("Построено " + lines.Count + " областей");
        }
        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;
            }
        }
Пример #22
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);
            }
        }
Пример #23
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);
            }
        }