Multi-symbol robots and indicators

Alex Kofman's avatar
Alex Kofman since: 20 Feb 2013; 
 13 Sep 2013, 12:26
Multi-symbol robots and indicators

We added new functionality to cAlgo - the ability for robots and indicators to work with multiple symbols. Now it's possible to use multiple symbol prices, OHLCV series and trade different symbols.

Requesting symbol

Robots and indicators can request a symbol specifying its symbol code. Symbol objects behave like the default Symbol object of a robot or indicator, containing current Ask, Bid, PipSize and other useful properties.

Symbol symbol = MarketData.GetSymbol("USDJPY");

Print("Symbol: {0}, Ask: {1}, Bid: {2}", symbol.Code, symbol.Ask, symbol.Bid);

Requesting OHLCV series

Robots and indicators can request OHLCV series for multiple symbols and timeframes and build indicators based on it.

MarketSeries series = MarketData.GetSeries("EURCAD", TimeFrame.Minute15);
MovingAverage ma = Indicators.SimpleMovingAverage(series.Close, 20);

Print("Symbol: {0}, TimeFrame: {1}", series.SymbolCode, series.TimeFrame);
Print("Last Close: {0}, Average Close: {1}", series.Close.LastValue, ma.Result.LastValue);

Trading multiple symbols

Robots in cAlgo can execute orders for different symbols. To do this, the robot must request the needed symbol by its code. Then, it will be possible to use it in a trade request:

 Symbol symbol = MarketData.GetSymbol("GBPCHF");
 ExecuteMarketOrder(TradeType.Buy, symbol, 10000);

The new version of our Demo cTrader and cAlgo is released and can be downloaded from www.spotware.com

Backtesting of Multi-symbol robots in not supported at least for now. It can be implemented in future.

TRADERS FIRST
Alex Kofman's avatar
Alex Kofman since: 20 Feb 2013; 
 13 Sep 2013, 12:36
Example: Multi-symbol RSI robot

Robot below trades EURUSD if both EURUSD and EURJPY are overbought or oversold according to RSI indicator:

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Requests;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class MultiSymbolRsiRobot : Robot
    {

        private const string MyLabel = "MultiSymbolRsiRobot";

        [Parameter("Periods", DefaultValue = 14)]
        public int Periods { get; set; }

        [Parameter("Volume", DefaultValue = 10000, MinValue = 1000)]
        public int Volume { get; set; }

        private RelativeStrengthIndex eurJpyRSI;
        private RelativeStrengthIndex eurUsdRSI;

        private Symbol eurUsd;

        protected override void OnStart()
        {
            var eurJpySeries = MarketData.GetSeries("EURJPY", TimeFrame);
            var eurUsdSeries = MarketData.GetSeries("EURUSD", TimeFrame);

            eurJpyRSI = Indicators.RelativeStrengthIndex(eurJpySeries.Close, Periods);
            eurUsdRSI = Indicators.RelativeStrengthIndex(eurUsdSeries.Close, Periods);

            eurUsd = MarketData.GetSymbol("EURUSD");
        }

        protected override void OnTick()
        {
            if (Trade.IsExecuting)
                return;

            if (eurUsdRSI.Result.LastValue > 70 && eurJpyRSI.Result.LastValue > 70)
            {
                ClosePosition(eurUsd, TradeType.Buy);
                OpenPosition(eurUsd, TradeType.Sell);
            }
            if (eurUsdRSI.Result.LastValue < 30 && eurJpyRSI.Result.LastValue < 30)
            {
                ClosePosition(eurUsd, TradeType.Sell);
                OpenPosition(eurUsd, TradeType.Buy);
            }
        }


        private void ClosePosition(Symbol symbol, TradeType tradeType)
        {
            foreach (Position position in Account.Positions)
            {
                if (position.Label == MyLabel && position.SymbolCode == symbol.Code && position.TradeType == tradeType)
                    Trade.Close(position);
            }
        }

        private void OpenPosition(Symbol symbol, TradeType tradeType)
        {
            if (HasPosition(symbol, tradeType))
                return;

            var request = new MarketOrderRequest(tradeType, Volume) 
            {
                Label = MyLabel,
                Symbol = symbol
            };

            Trade.Send(request);
        }

        private bool HasPosition(Symbol symbol, TradeType tradeType)
        {
            foreach (Position position in Account.Positions)
            {
                if (position.SymbolCode == symbol.Code && position.Label == MyLabel && position.TradeType == tradeType)
                    return true;
            }
            return false;
        }

    }
}
TRADERS FIRST
pennyfx since: 27 Sep 2012; 
 19 Sep 2013, 09:01
RE: Example: Multi-symbol RSI robot

Does this mean the following code will now return ALL open positions across all pairs ?  If so, this will probably break a lot of Robots.

foreach (Position position in Account.Positions)

Alex Kofman's avatar
Alex Kofman since: 20 Feb 2013; 
 19 Sep 2013, 09:15

This code was always like this - Account.Positions always contained positions for all symbols.

TRADERS FIRST
Alex Kofman's avatar
Alex Kofman since: 20 Feb 2013; 
 19 Sep 2013, 15:13
Indicator Example

Moving averages of several symbols on a single chart.



using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiSymbolMA : Indicator
    {
        private MovingAverage ma1, ma2, ma3;
        private MarketSeries series1, series2, series3;
        private Symbol symbol1, symbol2, symbol3;

        [Parameter(DefaultValue = "EURUSD")]
        public string Symbol1 { get; set; }

        [Parameter(DefaultValue = "EURAUD")]
        public string Symbol2 { get; set; }

        [Parameter(DefaultValue = "EURCAD")]
        public string Symbol3 { get; set; }

        [Parameter(DefaultValue = 14)]
        public int Period { get; set; }

        [Parameter(DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MaType { get; set; }

        [Output("MA Symbol 1", Color = Colors.Magenta)]
        public IndicatorDataSeries Result1 { get; set; }

        [Output("MA Symbol 2", Color = Colors.Red)]
        public IndicatorDataSeries Result2 { get; set; }

        [Output("MA Symbol 3", Color = Colors.Yellow)]
        public IndicatorDataSeries Result3 { get; set; }

        protected override void Initialize()
        {
            symbol1 = MarketData.GetSymbol(Symbol1);
            symbol2 = MarketData.GetSymbol(Symbol2);
            symbol3 = MarketData.GetSymbol(Symbol3);

            series1 = MarketData.GetSeries(symbol1, TimeFrame);
            series2 = MarketData.GetSeries(symbol2, TimeFrame);
            series3 = MarketData.GetSeries(symbol3, TimeFrame);

            ma1 = Indicators.MovingAverage(series1.Close, Period, MaType);
            ma2 = Indicators.MovingAverage(series2.Close, Period, MaType);
            ma3 = Indicators.MovingAverage(series3.Close, Period, MaType);
        }

        public override void Calculate(int index)
        {
            ShowOutput(symbol1, Result1, ma1, series1, index);
            ShowOutput(symbol2, Result2, ma2, series2, index);
            ShowOutput(symbol3, Result3, ma3, series3, index);
        }

        private void ShowOutput(Symbol symbol, IndicatorDataSeries result, MovingAverage movingAverage, MarketSeries series, int index)
        {
            int index2 = GetIndexByDate(series, MarketSeries.OpenTime[index]);
            result[index] = movingAverage.Result[index2];

            string text = string.Format("{0} {1}", symbol.Code, Math.Round(result[index], symbol.Digits));

            ChartObjects.DrawText(symbol.Code, text, index + 1, result[index], VerticalAlignment.Center, HorizontalAlignment.Right, Colors.Yellow);
        }

        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i >= 0; i--)
                if (time == series.OpenTime[i])
                    return i;
            return -1;
        }
    }
}
TRADERS FIRST
cAlgo Fanatic's avatar
cAlgo Fanatic since: 10 Jan 2013; 
 19 Sep 2013, 15:29
Indicator Example 2

Multiple symbol information displayed on the chart.

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiSymbolMarketInfo : Indicator
    {
        private Symbol symbol1;
        private Symbol symbol2;
        private Symbol symbol3;

        [Parameter(DefaultValue = "EURGBP")]
        public string Symbol1 { get; set; }

        [Parameter(DefaultValue = "GBPUSD")]
        public string Symbol2 { get; set; }

        [Parameter(DefaultValue = "EURUSD")]
        public string Symbol3 { get; set; }

        protected override void Initialize()
        {
            symbol1 = MarketData.GetSymbol(Symbol1);
            symbol2 = MarketData.GetSymbol(Symbol2);
            symbol3 = MarketData.GetSymbol(Symbol3);
        }

        public override void Calculate(int index)
        {
            if (!IsLastBar)
                return;

            var text = FormatSymbol(symbol1) + "\n" + FormatSymbol(symbol2) + "\n" + FormatSymbol(symbol3);

            ChartObjects.DrawText("symbol1", text, StaticPosition.TopLeft, Colors.Lime);
        }

        private string FormatSymbol(Symbol symbol)
        {
            var spread = Math.Round(symbol.Spread / symbol.PipSize, 1);
            return string.Format("{0}\t Ask: {1}\t Bid: {2}\t Spread: {3}", symbol.Code, symbol.Ask, symbol.Bid, spread);

        }
    }
}
TRADERS FIRST™
cAlgo Fanatic's avatar
cAlgo Fanatic since: 10 Jan 2013; 
 19 Sep 2013, 15:46
Correlation Coefficient

The correlation coefficient compares how currency pairs have moved in relation to each other.

The correlation coefficient formula is:

using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Indicators
{
    [Levels(-1, -0.5, 0, 0.5, 1)]
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, ScalePrecision = 2)]
    public class CorrelationCoefficient : Indicator
    {
        private MarketSeries series2;
        private Symbol symbol2;

        [Parameter(DefaultValue = "EURUSD")]
        public string Symbol2 { get; set; }

        [Parameter(DefaultValue = 22)]
        public int Period { get; set; }

        [Output("Correlation Coefficient", Color = Colors.Yellow)]
        public IndicatorDataSeries Result { get; set; }

        protected override void Initialize()
        {
            symbol2 = MarketData.GetSymbol(Symbol2);
            series2 = MarketData.GetSeries(symbol2, TimeFrame);
        }

        public override void Calculate(int index)
        {
            if (index < Period)
                return;

            double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0, sumY2 = 0;
            double x, y, x2, y2;

            int index2 = GetIndexByDate(series2, MarketSeries.OpenTime[index]);

            if (index2 == -1)
                return;

            for (int i = 0; i < Period; i++)
            {
                x = MarketSeries.Close[index - i];
                y = series2.Close[index2 - i];

                x2 = x * x;
                y2 = y * y;
                sumX += x;
                sumY += y;
                sumXY += x * y;
                sumX2 += x2;
                sumY2 += y2;
            }

            Result[index] = (Period * (sumXY) - sumX * sumY) / 
                               Math.Sqrt((Period * sumX2 - sumX * sumX) * (Period * sumY2 - sumY * sumY));
        }

        private int GetIndexByDate(MarketSeries series, DateTime time)
        {
            for (int i = series.Close.Count - 1; i >= 0; i--)
            {
                if (time == series.OpenTime[i])
                    return i;
            }
            return -1;
        }
    }
}
TRADERS FIRST™
Abhi  since: 31 Aug 2014; 
 23 Sep 2014, 22:16
Multi-symbol robots and indicators

Hi Spotware Team, nice improvements. I still cannot run average true range indicator on multiple symbols.

Please could you let us know when the feature will be available or if there is a way to get around the problem.

Thanks in advance.

Regards,

Abhi

cTrader Team's avatar
cTrader Team since: 23 Sep 2013; 
 24 Sep 2014, 09:56
RE: Multi-symbol robots and indicators

Abhi said:

Hi Spotware Team, nice improvements. I still cannot run average true range indicator on multiple symbols.

Please could you let us know when the feature will be available or if there is a way to get around the problem.

Thanks in advance.

Regards,

Abhi

Please specify what you mean by saying that. You can use multi-symbol data in code of your indicator. You can also add ATR to several charts.

TRADERS FIRST™ Vote for your favorite features: http://vote.spotware.com/
Abhi  since: 31 Aug 2014; 
 24 Sep 2014, 21:37
RE: RE: Multi-symbol robots and indicators

Spotware said:

Abhi said:

Hi Spotware Team, nice improvements. I still cannot run average true range indicator on multiple symbols.

Please could you let us know when the feature will be available or if there is a way to get around the problem.

Thanks in advance.

Regards,

Abhi

Please specify what you mean by saying that. You can use multi-symbol data in code of your indicator. You can also add ATR to several charts.

I want to show ATR for multiple symbols on a single chart. The  method call "Indicators.AverageTrueRange(int period , MovingAverageType.Exponential)" can be only called for a single symbol in a chart. Is there anyway to call ATR on multiple symbols and show up on a chart like you showed for RelativeStrengthIndex in this forum on previous posts.

Does it make sense now.