How to get bid/ask data from another Symbol than the Study or Strategy is running on?

Created at 18 Feb 2020, 16:06
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
DA

david.sanchez

Joined 07.02.2020

How to get bid/ask data from another Symbol than the Study or Strategy is running on?
18 Feb 2020, 16:06


Hi,

I want to use additional bid/ask data from a second symbol which would not be the one I am writing the script on.

to do something like this: Ask of data(1) - Bid of Data(2); data(1) = EURUSD and data(2) = EURCHF 

I tried this  https://ctrader.com/api/reference/symbols/getsymbol but it did not work.

I would be very grateful if anyone could help.

Regards

David 

 

 


@david.sanchez
Replies

PanagiotisCharalampous
19 Feb 2020, 08:14

Hi David,

That is the function you should use. Do you mind explaining what did you do and did not work?

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

david.sanchez
19 Feb 2020, 10:25

RE:

Hi Panagiotis

Thank you for your response.

I think I just typed in EURUSD in the field but I am not sure anymore.

Below you find what I am trying to achieve, it is code written for Multicharts, which I am trying to "translate".

BarsOfData(1) is for instance data from EURUSD.

I will recreate my code this week and will come back to you with a sample.

Sincerely,

David 

 

Multicharts code********************************************************************************

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using ATCenterProxy.interop;

namespace PowerLanguage.Strategy {
	public class ArbitrageMaster2 : SignalObject {
		public ArbitrageMaster2(object _ctx):base(_ctx)
		{
			Length = 10;
			Std = 1;
		}
		//All the Inputs needed are here
		[Input]
		public int Length { get; set; }
		[Input]
		public int Std { get; set; }

		private VariableSeries<Double> Ratio;
		private ISeries<double> b_Seriesdiff;



		private IOrderMarket m_long;
		private IOrderMarket m_short;
		private IOrderMarket m_lx;
		private IOrderMarket m_sx;

		//This function is for creating objects, note that market this bar is taken because once the spread is wide enough I want to enter the trade ASAP
		protected override void Create() 
		{
			Ratio = new VariableSeries<double>(this);
			

			m_long = OrderCreator.MarketThisBar(new SOrderParameters(Contracts.Default, EOrderAction.Buy));
			m_short = OrderCreator.MarketThisBar(new SOrderParameters(Contracts.Default, EOrderAction.SellShort));

			m_lx = OrderCreator.MarketThisBar(new SOrderParameters(Contracts.Default, EOrderAction.Sell));
			m_sx = OrderCreator.MarketThisBar(new SOrderParameters(Contracts.Default, EOrderAction.BuyToCover));
		}
		//This function initializes the first calculation
		protected override void StartCalc() 
		{
			b_Seriesdiff = new Lambda<Double>((_bb => ((BarsOfData(2).Close[_bb] - BarsOfData(1).Close[_bb]))));
		}

		//strategy logic is here, -std is the lower bound of the bollinger bands it is the standarddeviation which gets substracted from the mean
		protected override void CalcBar()
		{

			double oBB = b_Seriesdiff.BollingerBandCustom(Length, Std);
			double uBB = b_Seriesdiff.BollingerBandCustom(Length, -Std);

			Ratio.Value = BarsOfData(2).CloseValue - BarsOfData(1).CloseValue;

			if (Ratio.Value <= uBB)
			{
				m_short.Send();
				m_lx.Send();
			}

			if (Ratio.Value >= oBB)
			{
				m_long.Send();
				m_sx.Send();
			}
		}
	}
}

 


@david.sanchez

david.sanchez
24 Feb 2020, 10:01

RE:

Here you find the code I am trying to implement.

 

What am I doing wrong? 

How can I create a cross- pair spread (AUDUSD.ask - EURUSD.bid)?

 

using System;
using System.Linq;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Hedging2positionsonly : Robot
    {

        [Parameter("Max Spread", DefaultValue = 0.0, MinValue = -5.0)]
        public double MaxSpread { get; set; }

        string label = "Spread Test";

        protected override void OnStart()
        {
            var leg1 =public Symbol GetSymbol("AUDUSD");
            var leg2 =public Symbol GetSymbol("EURUSD");
            Spread = AUDUSD.Ask - EURUSD.Bid

    
        }

 


@david.sanchez

PanagiotisCharalampous
24 Feb 2020, 10:05

Hi David,

See below

            var symbol1 = Symbols.GetSymbol("AUDUSD");
            var symbol2 = Symbols.GetSymbol("EURUSD");
            var spread = symbol1.Ask - symbol2.Bid;

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

david.sanchez
24 Feb 2020, 10:41

RE:

PanagiotisCharalampous said:

Hi David,

See below

            var symbol1 = Symbols.GetSymbol("AUDUSD");
            var symbol2 = Symbols.GetSymbol("EURUSD");
            var spread = symbol1.Ask - symbol2.Bid;

Best Regards,

Panagiotis 

Join us on Telegram

 

wow, Thank you I will try it soon!


@david.sanchez

david.sanchez
25 Feb 2020, 21:30

RE: RE:

Hi Panagiotis,

Your Code helped a lot but I am not quite there.

Below you find everything the strategy will do.

However, it seems as if the cross pair spread is not usable for the Bollinger bands indicator.

How can I use it as intended below? 

In addition, is it possible to close and open positions in both instruments from the code as I tried below?

I would be very grateful if you could help me further on this issue.

If you need more information please let me know.

Sincerely,

David

using System;
using System.Linq;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Arbitrage1 : Robot
    {
       
      
        private BollingerBands bbds;

        protected override void OnStart()
        {
            var symbol1 = Symbols.GetSymbol("AUDUSD");
            var symbol2 = Symbols.GetSymbol("EURUSD");
            var spread = symbol1.Ask - symbol2.Bid;
            
            bbds = Indicators.BollingerBands(spread, 10,1,MovingAverageType.Simple);
    
        }
        protected override void OnTick()
        {
            
            var symbol1 = Symbols.GetSymbol("AUDUSD");
            var symbol2 = Symbols.GetSymbol("EURUSD");
            var spread = symbol1.Ask - symbol2.Bid;
            
            bbds = Indicators.BollingerBands(spread, 10,1,MovingAverageType.Simple);
            
            if (bbds >= spread) 
            {
                ExecuteMarketOrder(TradeType.Sell,"AUDUSD",100000);
                ExecuteMarketOrder(TradeType.Buy,"EURUSD",100000);
                
                if (position("AUDUSD") > 0)
                {
                    ClosePosition(?);
                }
                else if (Position("EURUSD") < 0)
                {
                    ClosePosition();
                }
                
            }
            else if (bbds <= spread)
            {
                ExecuteMarketOrder(TradeType.Buy,"AUDUSD",100000);
                ExecuteMarketOrder(TradeType.Sell,"EURUSD",100000);

                if (position("AUDUSD") < 0)
                {
                    ClosePosition(?);
                }
                else if (Position("EURUSD") > 0)
                {
                    ClosePosition();
                }
            }
                
        }
    }
}

 


@david.sanchez

PanagiotisCharalampous
26 Feb 2020, 08:47

Hi David,

1) You cannot use a double in Bollinger Bands constructor. It needs to be a DataSeries object.

2) You can open and close positions for any instrument you want but the code you have written doesn't make much sense. You can find all positions in Positions collection To close a position use the position.Close() function.

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

david.sanchez
26 Feb 2020, 10:09

RE:

 

Hi Panagiotis,

Thank you for your response.

Can I just change the datatype from "var" to "DataSeries"?

2) I will take a look on that, thank you!

Sincerely,

David Sanchez


@david.sanchez

PanagiotisCharalampous
26 Feb 2020, 10:16

Hi David,

No you can't. DataSeries is a series of values. A double is a single value. You will need to get the spread difference from a series of values before passing it to the BB indicator. I have the impression that you do not understand the API well. I would suggest you get some assistance from a professional instead of struggling with this yourself. 

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

david.sanchez
26 Feb 2020, 10:35

RE:

Hi Panagiotis

Yes, I contacted two professionals who offer coding services for ctrader. 

The first one declined my offer due to reasons which they did not tell me ( I did not demand a certain price).

The second one did not understand what a cross- pair spread is.

Now, I probably found a sample which looks like what I need 

Can I use  this "var _s2 = MarketData.GetSeries("EURUSD", TimeFrame)" to get bid/ask values of certain symbols?

Best Regards

Panagiotis


@david.sanchez

PanagiotisCharalampous
26 Feb 2020, 10:47

Hi David,

Can I use  this "var _s2 = MarketData.GetSeries("EURUSD", TimeFrame)" to get bid/ask values of certain symbols?

No you cannot. You can only get bid prices if you use t1 timeframe. However you can use MarketData.GetTicks() and construct a series out of it. See an example below

            var ticks = MarketData.GetTicks();
            var series = CreateDataSeries();
            int i = 0;
            foreach (var tick in ticks)
            {
                series[i] = tick.Ask;
                i++;
            }

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

david.sanchez
26 Feb 2020, 10:51

RE:

Hi Panagiotis,

Alright, this looks like all the pieces I need.

Thank you a lot!

Have a nice day!

David

 

 


@david.sanchez

david.sanchez
26 Feb 2020, 21:23

RE: RE:

So I tried to use it but I still need some help

            //Am I supposed to write "AUDUSD" in here? How would it otherwise be clear from where to draw tick data?

            var ticks = MarketData.GetTicks("AUDUSD");
            var series = CreateDataSeries();
            int i = 0;
            foreach (var tick in ticks)
            {
                series[i] = tick.Ask;
                i++;
            }

            var ticks2 = MarketData.GetTicks("EURUSD");
            var series2 = CreateDataSeries();
            int t = 0;
            foreach (var tick in ticks)
            {
                series2[t] = tick.Bid;
                t++;
            }

            

           var Spread = CreateDataSeries();
           
            for (int X = 0; X < 10; X++)
            {
               
                Spread[X] = series[X] - series2[X];
               
            }


            var bbds = Indicators.BollingerBands(Spread, 10, 1, MovingAverageType.Simple);//upper Bollinger band
            var bbds2 = Indicators.BollingerBands(Spread, 10, -1, MovingAverageType.Simple)//lower Bollinger band

            /*up to here everything seems to work (no error messages)

            here it says that the logic operations cannot be applied to types of "bollinger bands" and "double", How can I solve this?*/

            if (bbds >= Spread[0]) 
            {
                ExecuteMarketOrder(TradeType.Sell,"AUDUSD",100000);
                ExecuteMarketOrder(TradeType.Buy,"EURUSD",100000);

                ...

            }

I would be very grateful if you could help me on this last issue...

Sincerely,

David Sanchez


@david.sanchez

PanagiotisCharalampous
27 Feb 2020, 08:20

Hi David,

You need to explain what are you trying to do at that point.

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

david.sanchez
27 Feb 2020, 10:50 ( Updated at: 21 Dec 2023, 09:21 )

RE:

Hi Panagiotis,

This will be a long post because I want to describe and explain it as detailed as possible. Please stick with me because I am certain that solving this issue will be of great value for the community since forex markets have unique mathematical relationships between pairs. It is necessary to subtract, add, multiply or divide two or multiple pairs for analyzing those mathematical relationships. In my case I want to trade cross- pairs spread, which is the subtraction of two different pairs, EURUSD - AUDUSD for instance. So whenever I mention spread I am talking about these spreads: cross- pair spreads.

Note that this particular spread is nonsense it is just for illustration purposes. Imagine this spread would generate the attached charts at the end of this post.

there are three panels:

Panel 1 shows the result of EURUSD - AUDUSD (not really, just for the sake of the explanation) in green

Panel 1 shows the Bollinger bands on that spread in cyan

Panel 1 shows the SMA on that spread in pink

Panel 2 shows EURUSD, the first leg of the spread

Panel 3 shows AUDUSD, the second leg of the spread

*Those setups were created with multicharts.NET the entry and exits are marked with arrows.

As you can see the chart on panel 1, which is the cross pair spread itself, EURUSD - AUDUSD, goes sideways. This implements, that there is "no" significant risk on the up- nor on the downside. This makes this strategy market-neutral.

So the goal is to scalp the spread, selling when it is expensive, buying when it is cheap. 

Therefore a suitable indicator would be Bollinger bands since they add and subtract a given standard deviation on and from a simple moving average.

So if the current value of the spread is >= the upper bound then sell the spread and if the current value is <= the lower bound, buy it. 

Now selling the spread means: Sell EURUSD (the first leg) and buy AUDUSD (the second leg) because we want to hedge ourselves against market risk. And since we encountered a situation where the spread is overpriced it should reverse to its mean and we can "lock" profits. The beauty is, that is irrelevant how it returns to its mean or to the other extreme. Whether EURUSD goes up or AUDUSD goes down or something in between does not matter to us.

Sample: EURUSD = 4; AUDUSD = 2 => Spread value = 2 (EURUSD - AUDUSD); Sell the spread = Sell EURUSD and buy AUDUSD

Mean = 0 

If EURUSD down goes to 2 then 2 dollars profit with the short no profit or loss with the long = 2 Dollars of profit.

or 

If AUDUSD goes up to 4 Dollars then 2 Dollars profit with the long and nothing with the short.

on the charts, the trade is exited not when reaching the mean but actually when reaching the other side/ extreme of the Bollinger bands (from upper to lower bound and vice versa). This generates less commission.

Perfect isn't it?

There is no point in waiting for a close of a bar and since we want to get in as fast as possible (because we want both trades, Buy EURUSD and Sell AUDUSD, to happen simultaneously) we want to use market orders.

This brings a new dynamic into play. 

Buy Marketorders get executed at Ask prices and Sell Market orders at Bid prices.

So instead of just doing this: EURUSD - AUDUSD

We do this: Ask of EURUSD - Bid of AUDUSD

You probably noticed that it gets pretty complicated from here on because for buy trades we would need EURUSD.Ask - AUDUSD.Bid and for exit trades EURUSD.Bid - AUDUSD.Ask 

Because buying the spread is buying EURUSD at ask and selling AUDUSD at bid and selling the spread is seling EURUSD at bid and buying AUDUSD at ask.

All I need is to know is how to write the first part which is:

if  current value of (EURUSD.Ask - AUDUSD.Bid) is equal or greater than upper bound of Bollinger bands(EURUSD.Ask - AUDUSD.Bid) 

In my code above (last post) I seem to have been able to write everything correctly until the condition of the if method, there it shows an error:

"here it says that the logic operations cannot be applied to types of "Bollinger bands" and "double", How can I solve this?"

 

With the ability to use subtraction, addition, division and multiplication between two or more different pairs and then using that result in indicators and if statements we are able to explore a lot more trading possibilities because of the mathematical relationships in the forex markets which are unique to them. 

So bottom line: I want to subtract EURUSD.Ask from AUDUSD.bid and use that in the Bollinger bands indicator and for the logic of the if statement for entering and exiting trades with the <>= operations.

It would be really a pity if this potential stays unattainable.

I really really appreciate your time and your support.

Sincerely,

David Sanchez

***********************attachment***************************************************

compare the dates to find the identical trades.

Chart for first leg

chart for the second leg (note how it does the opposite of the first leg)


@david.sanchez

PanagiotisCharalampous
27 Feb 2020, 10:58

Hi David,

Unfortunately I do not have time to study your strategy neither I can engage in custom development. It would be easier to stick to the technical questions you have related to the use of the API. If what you are looking for is to check the values of the Bollinger Bands then you can find these values in the Top, Bottom, Main data series. Check the reference here

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

david.sanchez
27 Feb 2020, 11:03

RE:

Hi Panagiotis,

Excuse me, I did not mean to let you study my strategy or engage in custom development. I thought this was your expectation for my explanation of what I am trying to do.

I will try it soon.

Sincerely,

David 

 


@david.sanchez

PanagiotisCharalampous
27 Feb 2020, 11:07

Hi David,

I was actually asking what are you trying to do at the specific line of code where you get an error. What are you trying to compare? On a higher level we are all trying to do the same thing, make money :).  

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

david.sanchez
27 Feb 2020, 11:59

RE:

On a higher level we are all trying to do the same thing, make money :) - that's true ^^

With the following lines, I tried to get bid/ask data for those two pairs as a series, because Bollinger bands can only be used with series inputs.

Are they used correcly? Note that I typed in the actual pairs which were not in your sample..., so probably false?

           var ticks = MarketData.GetTicks("AUDUSD");
            var series = CreateDataSeries();
            int i = 0;
            foreach (var tick in ticks)
            {
                series[i] = tick.Ask;
                i++;
            }

            var ticks2 = MarketData.GetTicks("EURUSD");
            var series2 = CreateDataSeries();
            int t = 0;
            foreach (var tick in ticks)
            {
                series2[t] = tick.Bid;
                t++;
            }

With the next lines I tried to subtract both series so that I can use it in the Bollinger bands indicator

            var Spread = CreateDataSeries();
           
            for (int X = 0; X < 10; X++)
            {
               
                Spread[X] = series[X] - series2[X];
               
            }

On these lines I wanted to declare variables for the upper and lower bound of Bollinger bands calculated on the spread series, is this done correctly? 

            var bbds = Indicators.BollingerBands(Spread, 10, 1, MovingAverageType.Simple);//upper Bollinger band
            var bbds2 = Indicators.BollingerBands(Spread, 10, -1, MovingAverageType.Simple)//lower Bollinger band

At last here I want to test if the current value of the Spread series Spread[0] is overpriced, equal or more than upper bollinger band.

What are you trying to compare?

"bbds" is supposed to be the upper bollinger band calculated on the spread series and Spread[0] the current result of EURUSD.Ask[0] - AUDUSD.Bid[0]

 if (bbds >= Spread[0]) 
            {
                ExecuteMarketOrder(TradeType.Sell,"AUDUSD",100000);
                ExecuteMarketOrder(TradeType.Buy,"EURUSD",100000);

             }

Is it more or less clear ? If you need more information, please let me know.

Regards

David

***Note: if there is anyone closely following this post I am still looking for someone who could do this for me, of course, paid.

 


@david.sanchez

PanagiotisCharalampous
27 Feb 2020, 12:04

Hi David,

Thanks for the clarification. As explained above, you can find these values in the Top, Bottom, Main data series of each Bollinger Band. Check the reference here

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

david.sanchez
28 Feb 2020, 10:15

Hi Panagiotis,

So it seems to solve that particular issue, now there were no error messages and I was able to compile the code.

However, When I tried to run the cbot on EURUSD ( I added EURUSD to the code through the "+" sign beow the code in ctrader) it stopped itself after a few seconds.

So I assume there is something in the code which is not properly used.

I suspect either these lines: 

var ticks = MarketData.GetTicks("AUDUSD");

Are the brackets supposed to be left out empty? I could not find the correct API reference to check it myself...

-If yes how can I get Bid/ Ask data as Series for particular pairs like AUDUSD and EURUSD?

Or these lines might cause it to stop:

var Spread = CreateDataSeries();

            for (int X = 0; X < 10; X++)
            {

                Spread[X] = series[X] - series2[X];

            }

"series" is supposed to be the Ask dataseries of AUDUSD and "series2" Bid of EURUSD

since I want to use the difference of both series in the bollinger bands, I did it that way.

or maybe it is somewhere else here is the entire code:

using System;
using System.Linq;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Requests;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Arbitrage1 : Robot
    {
       
      
        private BollingerBands bbds;

        protected override void OnStart()
        {
                       
            var ticks = MarketData.GetTicks("AUDUSD");
            var series = CreateDataSeries();
            int i = 0;
            foreach (var tick in ticks)
            {
                series[i] = tick.Ask;
                i++;
            }

            var ticks2 = MarketData.GetTicks("EURUSD");
            var series2 = CreateDataSeries();
            int t = 0;
            foreach (var tick in ticks)
            {
                series2[t] = tick.Bid;
                t++;
            }

            var Spread = CreateDataSeries();

            for (int X = 0; X < 10; X++)
            {

                Spread[X] = series[X] - series2[X];

            }

            var bbds = Indicators.BollingerBands(Spread, 10, 1, MovingAverageType.Simple);

        }
        protected override void OnTick()
        {
                        
            var ticks = MarketData.GetTicks("AUDUSD");
            var series = CreateDataSeries();
            int i = 0;
            foreach (var tick in ticks)
            {
                series[i] = tick.Ask;
                i++;
            }

            var ticks2 = MarketData.GetTicks("EURUSD");
            var series2 = CreateDataSeries();
            int t = 0;
            foreach (var tick in ticks)
            {
                series2[t] = tick.Bid;
                t++;
            }

            var Spread = CreateDataSeries();
           
            for (int X = 0; X < 10; X++)
            {
               
                Spread[X] = series[X] - series2[X];
               
            }
                       
                      
            if (bbds.Top[0] <= Spread[0]) 
            {
                ExecuteMarketOrder(TradeType.Sell,"AUDUSD",100000);
                ExecuteMarketOrder(TradeType.Buy,"EURUSD",100000);

                var openPositions1 = Positions.FindAll("Arbitrage1", "AUDUSD");

                foreach (var order in openPositions1)
                {
                    ClosePosition(order);
                }

                var openPositions2 = Positions.FindAll("Arbitrage1", "EURUSD");

                foreach (var order in openPositions2)
                {
                    ClosePosition(order);
                }

            }
            else if (bbds.Bottom[0] >= Spread[0])
            {
                ExecuteMarketOrder(TradeType.Buy,"AUDUSD",100000);
                ExecuteMarketOrder(TradeType.Sell,"EURUSD",100000);

                var openPositions1 = Positions.FindAll("Arbitrage1", "AUDUSD");

                foreach (var order in openPositions1)
                {
                    ClosePosition(order);
                }

                var openPositions2 = Positions.FindAll("Arbitrage1", "EURUSD");

                foreach (var order in openPositions2)
                {
                    ClosePosition(order);
                }

            }
                
        }
    }
}

I appreciate your support.

Sincerely,

David


@david.sanchez

PanagiotisCharalampous
28 Feb 2020, 10:24 ( Updated at: 21 Dec 2023, 09:21 )

Hi David,

If you check your log you will see the reason your cBot stops

This happens because bbds is never initialized

  private BollingerBands bbds;

The compiler warns you about this

Instead you seem to initialize a local variable which is not used anywhere

 var bbds = Indicators.BollingerBands(Spread, 10, 1, MovingAverageType.Simple);

I still believe it is not a good idea to do this yourself. Better let a professional do the job for you. Maybe you can send them this discussion as an attempt to explain them what are you trying to do.

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

david.sanchez
28 Feb 2020, 10:45

RE:

Panagiotis,

Thank you for your advice.

I will give it a second try, maybe you are right and they are now capable of doing it.

Sincerely,

David 


@david.sanchez