softwarespartan / IB4m

Interactive Brokers API for Matlab
GNU General Public License v2.0
62 stars 21 forks source link

Download markPrice #128

Closed achille1112 closed 3 years ago

achille1112 commented 3 years ago

Hello, I have a problem when I trie to dowload markPrice data of more than one instrument with reqMktData method.

If I run the following code:

clear all; close all; clc;

percorso = 'W:\Software\IB4m-master\IB4m-master';

addpath(percorso); addpath(percorso,fullfile(percorso,'docs'))
javaaddpath(fullfile(percorso,'Jar','TWS973.jar'))

strumenti = {'EUR';'AZM';'BGN';'BMED';'BZU';'LDO'};

P_TOT = [];

% get TWS session instance
session = TWS.Session.getInstance();

% connect to TWS
session.eClientSocket.eConnect('127.0.0.1',7496,0);

reqId = 0;

genericTickList = '221';

for i = 1:length(strumenti)

    % create local buffer for market metadata events with size 1000
    [metabuf,metalh] = TWS.initBufferForEvent(TWS.Events.MARKETMETADATA,1000);

    % create an empty stock contract
    contract = com.ib.client.Contract();

    if ~strcmp(strumenti{i},'EUR')

        contract.symbol(strumenti{i})
        contract.exchange('SMART');
        contract.primaryExch('BVME');
        contract.currency('EUR');
        contract.secType('STK');

    else

        contract.exchange('IDEALPRO');
        contract.localSymbol('EUR.USD');
        contract.currency('USD');
        contract.secType('CASH');

    end

    reqId = reqId + 1;

    session.eClientSocket.reqMktData(reqId,contract,genericTickList,false,false,[]); pause(1);

    mktDataEvents = collection2cell(metabuf);

    pause(5)

    vecValue = [];

    for j = 1:numel(mktDataEvents)

        e = mktDataEvents{j};

        if strcmp(string(e.data.key),'markPrice')

            vecValue = [vecValue;str2double(e.data.value)];

        end

    end

    lastMarkPrice = vecValue(end);

    P_TOT = [P_TOT,lastMarkPrice];

    clear metabuf metalh

end

P_TOT = round(P_TOT,4)

The value of P_TOT is:

P_TOT =

    1.2156    1.2156   34.3000    1.2156   23.2300    1.2155

which is obviously wrong! Why does this happen?

Best Regards. Domenico

giovannetti87 commented 3 years ago

Ciao Domenico,

I tried your code with only one instrument (EUR) and it appears I can feed the data. However, it is very slow. This is myt first dip into java handlers hence I am sure I should not use a while loop to operate your script, but I fall short of intuition on what to do next in order to have a data-stream downloaded on my matlab if you have any idea or made any progress, I would be grateful to hear from you!

achille1112 commented 3 years ago

Ciao Giovannetti, if you want data-stream downloaded on your matlab just set the buffer size in my code (in my code is 1000) and when you need the data you use mktDataEvents = collection2cell(metabuf);

In this mode you can obtain the data until you have reached the size of the buffer.

Domenico

giovannetti87 commented 3 years ago

Hey man thanks for coming back so promptly!!

Ok, I see. I'm sorry for the dumb question but, if I only call mktDataEvents, will the fresh data be pulled out from the stream? Or I should call up everything up to reqMktData, that is:

   reqId = reqId + 1;

    session.eClientSocket.reqMktData(reqId,contract,genericTickList,false,false,[]); pause(1);

    mktDataEvents = collection2cell(metabuf);

    pause(5)

    vecValue = [];

    for j = 1:numel(mktDataEvents)

        e = mktDataEvents{j};

        if strcmp(string(e.data.key),'markPrice')

            vecValue = [vecValue;str2double(e.data.value)];

        end

    end

    lastMarkPrice = vecValue(end);

    P_TOT = [P_TOT,lastMarkPrice];

This is what I would do with a REST protocol. But I was under the impression that with these java handlers the data stream is automatic and constant with no need of call-back functions or while loop?

thanks a lot, I (and certainly many others!!) really appreciate

achille1112 commented 3 years ago

Ciao Giovanetti, You just use:

mktDataEvents = collection2cell(metabuf);

and so you can extract the data from the buffer. Howewer you can refer to the following link:

[https://github.com/softwarespartan/IB4m/issues/8]

Best Regards Domenico.

giovannetti87 commented 3 years ago

Hi Domenico,

I see what you mean!

Just as a check, I pulled the data using:

while 3 < 4 cellfun(@(e)disp(e.data),collection2cell(metabuf)) pause(0.2) end

after fixing a buffer of size 1.

One question: why would we use a larger buffer, if we can locally store the buffer in some vector?

Despair2000 commented 3 years ago

The buffer catches the events from the API. These events come asynchronous (at irregular intervals) so you want to have a little larger buffer to avoid that you miss an event in case your program is just busy doing something else when an event drops in. Depending on what you are looking at (the number of potential events) you want different sizes for the buffer. For MarketData I for example usually use 50 though the default size of 32 is probably just as fine. For account data I use a size of 200 (there can come quite a lot of events). A size of 1000 as suggested above is surely overkill though . This of course also depends on how often you check the buffer content.

giovannetti87 commented 3 years ago

Hi Despair,

I see, the explanation makes perfect sense. I still have to familiarize with the buffer object, but I assume for each information a buffer collects, there will be a timestamp to chronologically discipline the received buffer data and pick out of it only the "last" occurring events?

thanks again both.

Despair2000 commented 3 years ago

There is no timestamp but these are FIFO (first in first out) buffers meaning the first event in the buffer is always the most recent. When the buffer is full the oldest event drops out.

giovannetti87 commented 3 years ago

ok, excellent.

softwarespartan commented 3 years ago

@giovannetti87 keep in mind that "buffers" are just a single "pattern" of how to process events. It is not required to put events in a buffer, per se. It is possible to create a callback that processes the data event directly. Also, it is possible to create many callbacks for a single event. Each callback registered for an event will each receive a copy of the event and "do their thing". Note that IB4m is event based because the IB API itself is event based (i.e. receives events from the TWS).

Each event should have a date object associated with it (e.g. event.data and event.date)

At any rate, be sure to read up on events and listeners in MATLAB:

https://www.mathworks.com/help/matlab/matlab_oop/events-and-listeners-concepts.html

Don't hesitate to reach out if need additional help.

giovannetti87 commented 3 years ago

hey @softwarespartan, I'm truly happy of having the chance to say thank you for your great work. Sure, I'll look into that.

thanks again

giovannetti87 commented 3 years ago

Another question I would like to ask, in the hope It's not a nuisance, I don't understand whether I can get the usual bid/ask spread under the generic tick list provided by IBKR. In the example file we have a vector of generic ticks which I could retrieve in the generic tick list available on IBKR. However, it appears that the mapping changed, is that possible? For example, the '221' tick used in the code kindly supplied by Domenico maps into a "creditmanmark price" which the site states as "not currently available". does it make sense? thanks and apologies for the naive question

Despair2000 commented 3 years ago

Bid and ask (and some more) you receive by default without even specifying a tick list. Here you find the list of available ticks: https://interactivebrokers.github.io/tws-api/tick_types.html

achille1112 commented 3 years ago

Exactly as Despair says! I had set the tick list only in the various tests I did.

Domenico.

giovannetti87 commented 3 years ago

Hi guys,

thanks a lot for the patience. I think the problem was that I was insisting in downloading the metabuf rather than the databuf. Now everything works perfectly fine with one instrument, and I could plot a nice dynamic graph with bid/ask prices just as a check.

Now I was trying to run an experiment similar to the one of Domenico, that is mixing multiple data-sources. I subscribed to three data-streams (eur.usd, eur.gbp and gbp.usd) and I am trying to discipline these in 3 vectors. To do so, I tried the function kindly provided by softwarespartan, map.get(databuf.get().data.reqId)

To do so, I created

map.put(reqId,contract.localSymbol);

with the intention of linking each element of the buffer to its currency pair. Then, I placed

mktDataEvents = collection2cell(databuf); map.get(databuf.get().data.reqId)

with the intention to have the function called every time market data events are pulled out. I can see that for each iteration map.get pulls one of the three crosses, but I'm puzzled by the fact that in the argument of map.get it appears that map.get is linked to one specific stream line, given by the reqId. How is it possible that every time it provides a different answer?

thanks, this group is amazing.

Despair2000 commented 3 years ago

I usually avoid the problem of having to do the book keeping by creating one buffer for every symbol I want to watch. You create the buffers with the provided function initMarketDataBufferWithReqId.m. I streamed this way up to 100 symbols without problems.

giovannetti87 commented 3 years ago

Hey Despair, thanks for the ultimate tip. I think I nailed it. I can stream all the pairs flawless now.

For those interested, I recommend to read also Abel's post in the following discussion:

https://github.com/softwarespartan/IB4m/issues/8

Domenico, happy to share my code if you want to have a look

thanks

achille1112 commented 3 years ago

Thanks Giovanetti, I solved the problem!

Domenico

giovannetti87 commented 3 years ago

That's great! By the way, I am building, out of sheer curiosity, a forex arbitrageur using some simple result of linear programming on generalized network flows. Given the 100 stream limit, we have (x^2 - x)/2 = 100 -> x= 14 currencies which map into a max of 196 variables for the optimization problem. Inversion of a 196x196 matrix doesn't look too crazy with a contemporary gaming laptop, but I was wondering, if anybody here already tried a similar approach, whether the result is worth the effort given IBKR spreads.

Despair2000 commented 3 years ago

I can't say anything to this but I'd recommend you to start a new thread when you start a new discussion (and maybe close the ones that are finished). If you comment in an existing thread nobody will see it accept the people participating within the thread.

giovannetti87 commented 3 years ago

right, sorry.