amittleider / AutoFinance.Broker

A Dotnet Core library to interact with Interactive Broker's Trader Workstation (IB TWS)
32 stars 16 forks source link

can't request streaming market data #36

Open Neznakomec opened 2 years ago

Neznakomec commented 2 years ago

As I see TwsControllerBase::RequestMarketDataAsync method written in a way to get something, then omit all callbacks and stop listening any data.

What to do if I want to receive a stream of quotes?

amittleider commented 2 years ago

Hi @Neznakomec ,

There is a test here https://github.com/amittleider/AutoFinance.Broker/blob/09d40057bdf70859aaa8fab8abca4890700b5cdb/AutoFinance.Broker.IntegrationTests/InteractiveBrokers/Controllers/TwsControllerBaseTests.cs#L669 which you can use as a template for your production code.

In short, for a streaming API, you will need to register to the MarketData events or TickEvents (or others) that are located on the TwsBaseController, like this:

twsCallbackHandler.MarketDataTypeEvent +=
                (sender, args) => { myfunc(args.x); };
twsCallbackHandler.TickPriceEvent +=
                (sender, args) => { myfunc(args.x) };

It's not impossible that there's a bug here. This API was not originally intended for streaming data (it works better for things that have a real "end", like placing orders, requesting historical data, searching contracts, etc.; and less good for streaming, which has no real end). It may be the case that simply using the client socket will be easier in the case of streaming.

Your contributions are welcome. If you use the integration tests project, please be sure to sign into Trader Workstation with your test credentials. The integration tests place real orders, so you wouldn't want to be running them against a prod account.

Neznakomec commented 2 years ago

I'm also don't know a good solution for streaming market data, may be just return an identifier

if (snapshot == false) {
   taskSource.SetResult(new TickSnapshotEndEventArgs(tickerId));
}

and leave the user to choose what to do with event handling

amittleider commented 2 years ago

Indeed, the user will have to register their own event handling. It may not make sense to follow the pattern of TaskSource when it comes to this type of API.

If you want to make a prototype, I'd be happy to review it.

On Wed, Aug 17, 2022 at 4:50 PM Neznakomec @.***> wrote:

I'm also don't know a good solution for streaming market data, may be just return an identifier

if (snapshot == false) { taskSource.SetResult(new TickSnapshotEndEventArgs(tickerId)); }

and leave the user to choose what to do with event handling

— Reply to this email directly, view it on GitHub https://github.com/amittleider/AutoFinance.Broker/issues/36#issuecomment-1218115113, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMM6X5X6SUC23I63QXYJ4DVZT3ZVANCNFSM56UXQDGQ . You are receiving this because you commented.Message ID: @.***>

hftcryptobot commented 2 years ago

@amittleider Hi, thanks for API. I have also used an example from [TwsControllerBaseTests.cs] to get ticks for MSFT, and it works, but the problem is that this work only about 1 minute... After 1 minute, no new ticks :) And how to get order book subscription?

hftcryptobot commented 2 years ago

Found in code limitation for 1 minute. Why did you do this? :)

Neznakomec commented 2 years ago

For the case of using snapshot=true this cancelling not required, cause TWS API do it for you: it opens subscription for 11 seconds maximum, tries to collect all appropriate tick types, then closes subscription with tickSnapshotEnd event. Of course you can cancel subscription by tickerId(request identifier) earlier, if you want to free a market data line (which is about 100 data lines by default) earlier.

hftcryptobot commented 2 years ago

"What to do if I want to receive a stream of quotes?" - Have you find the realization? Or if you have done for yourself. Can you share pls?

Neznakomec commented 2 years ago

@hftcryptobot I think you can use TwsControllerBase::RequestMarketDataAsync, but you should omit the moment with cancelling market data after 1 min.

Then, you can use callbacks and catch the events as described in 2nd message of this thread.

Although, it can be possible that TWS API won't send you anything (it's probably a bug, or a strange behaviour - you're subscribing on instrument market data, no any errors and exceptions, security described correctly...But there are no ticks coming out of TWS API for this security). Then TwsControllerBase::RequestMarketDataAsync without that 1-minute stop and cancel will be an endless method, that's bad...

Neznakomec commented 2 years ago

So, probably the solution is

            CancellationTokenSource tokenSource = new CancellationTokenSource(60 * 1000);
            tokenSource.Token.Register(() =>
            {
                // this.CancelMarketData(tickerId);

                this.twsCallbackHandler.TickPriceEvent -= tickPriceEventHandler;
                this.twsCallbackHandler.TickSizeEvent -= tickSizeEventHandler;
                this.twsCallbackHandler.TickStringEvent -= tickStringEventHandler;
                this.twsCallbackHandler.TickGenericEvent -= tickGenericEventHandler;
                this.twsCallbackHandler.TickOptionComputationEvent -= tickOptionComputationEventHandler;
                this.twsCallbackHandler.TickSnapshotEndEvent -= tickSnapshotEndEventHandler;
                this.twsCallbackHandler.TickEFPEvent -= tickEFPEventHandler;
                this.twsCallbackHandler.ErrorEvent -= errorEventHandler;

                // taskSource.TrySetCanceled();
                taskSource.TrySetResult(new TickSnapshotEndEventArgs(args.TickerId));
            });

I don't sure about taskSource.TrySetCanceled();, probably we shouldn't raise a TaskCancelledException. It will interfere our pipeline.

hftcryptobot commented 2 years ago

``

@hftcryptobot I think you can use TwsControllerBase::RequestMarketDataAsync, but you should omit the moment with cancelling market data after 1 min.

Then, you can use callbacks and catch the events as described in 2nd message of this thread.

Although, it can be possible that TWS API won't send you anything (it's probably a bug, or a strange behaviour - you're subscribing on instrument market data, no any errors and exceptions, security described correctly...But there are no ticks coming out of TWS API for this security). Then TwsControllerBase::RequestMarketDataAsync without that 1-minute stop and cancel will be an endless method, that's bad...

RequestMarketDataAsync can return orderbook? The cancellation for 1 minute I have fixed..

Neznakomec commented 2 years ago

@hftcryptobot no, this method not designed to work with level 2 and orderbook. You can use TwsControllerBase::RequestMarketDataAsync only for level 1 market data ticks.

I'm sorry to say that, but the support of market depth (reqMktDepth + updateMktDepth, updateMktDepthL2) not covered in this wrapper library yet: https://interactivebrokers.github.io/tws-api/market_depth.html

Probably, you can directly call method: twsObjectFactory.ClientSocket.EClientSocket.reqMarketDepth