amittleider / AutoFinance.Broker

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

'A task was cancelled' on PlaceOrder #41

Open CoolDixon opened 9 months ago

CoolDixon commented 9 months ago

I always get 'a task was cancelled' exception on PlaceOrder operations. Other works just fine

`

        Log.Information("\nOpen Orders:");
        List<OpenOrderEventArgs> openOrdersStatusEvents = await twsController.RequestOpenOrders();
        foreach (OpenOrderEventArgs e in openOrdersStatusEvents)
            Log.Information($"Contract={e.Contract}. ID={e.OrderId} Order={e.Order.OrderType}/{e.Order.TotalQuantity} Status={e.OrderState.Status}");

        Contract contract = new Contract
        {
            SecType = TwsContractSecType.Stock,
            Symbol = "MSFT",
            Exchange = TwsExchange.Smart,
            PrimaryExch = TwsExchange.Island,
        };

        Order order = new Order
        {
            Action = TwsOrderActions.Buy,
            OrderType = TwsOrderType.Market,
            TotalQuantity = 1,
            Tif = "GTC",
            Transmit = false
        };

        int orderId = await twsController.GetNextValidIdAsync();
        Log.Information($"OrderID={orderId}");
        bool successfullyPlaced = await twsController.PlaceOrderAsync(orderId, contract, order);
        Log.Information($"Placed Order: {successfullyPlaced}");

`

I even see the order in the IB Gateway log window, but it is not placed at last

What am I missing?

Thanks in advance

amittleider commented 9 months ago

Can you try setting transmit to true please?

Le sam. 9 déc. 2023, 11 h 32, CoolDixon @.***> a écrit :

I always get 'a task was cancelled' exception on PlaceOrder operations. Other works just fine

` Log.Information("\nOpen Orders:"); List openOrdersStatusEvents = await twsController.RequestOpenOrders(); foreach (OpenOrderEventArgs e in openOrdersStatusEvents) Log.Information($"Contract={e.Contract}. ID={e.OrderId} Order={e.Order.OrderType}/{e.Order.TotalQuantity} Status={e.OrderState.Status}");

    Contract contract = new Contract
    {
        SecType = TwsContractSecType.Stock,
        Symbol = "MSFT",
        Exchange = TwsExchange.Smart,
        PrimaryExch = TwsExchange.Island,
    };

    Order order = new Order
    {
        Action = TwsOrderActions.Buy,
        OrderType = TwsOrderType.Market,
        TotalQuantity = 1,
        Tif = "GTC",
        Transmit = false
    };

    int orderId = await twsController.GetNextValidIdAsync();
    Log.Information($"OrderID={orderId}");
    bool successfullyPlaced = await twsController.PlaceOrderAsync(orderId, contract, order);
    Log.Information($"Placed Order: {successfullyPlaced}");

`

I even see the order in the IB Gateway log window, but it is not placed at last

What am I missing?

Thanks in advance

Carlos

— Reply to this email directly, view it on GitHub https://github.com/amittleider/AutoFinance.Broker/issues/41, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMM6X5FSZJF7VY73AEUWA3YIQ44LAVCNFSM6AAAAABANWNX3GVHI2DSMVQWIX3LMV43ASLTON2WKOZSGAZTGNZYGYZTMMI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

CoolDixon commented 9 months ago

Ouch! I would have bet I already tried that too. That's it, thanks! and sorry for the dummyest question ever

As for the testings with AmiBroker IBController it allows to leave it untransmitted I just set it to false while testing.

By the way, is it possible to access transaction commissions costs in any way? I tried with RequestExecutions but seems it is not available from there

amittleider commented 9 months ago

The transmit param allows you to submit multiple orders simultaneously. It's especially useful for bracket orders,and you can check out the placebracketorder method to see an example.

I'm surprised you can't get commissions from the executions. Maybe it's missing from this wrapper. You should check IB docs. Feel free to add support

Le dim. 10 déc. 2023, 19 h 08, CoolDixon @.***> a écrit :

Ouch! I would have bet I already tried that too. That's it, thanks! and sorry for the dummyest question ever

As for the testings with AmiBroker IBController it allows to leave it untransmitted I just set it to false while testing.

By the way, is it possible to access transaction commissions costs in any way? I tried with RequestExecutions but seems it is not available from there

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

CoolDixon commented 8 months ago

I had to include CommissionsReport onto Execution report within the wrapper. It is working fine now.

But I still have problems with the transmit = false, i get "A task was cancelled" exception. In fact I get it quite often, I have to retry lot of operations. Is it normal?

amittleider commented 8 months ago

I had to include CommissionsReport onto Execution report within the wrapper. It is working fine now.

But I still have problems with the transmit = false, i get "A task was cancelled" exception. In fact I get it quite often, I have to retry lot of operations. Is it normal?

No, that's not normal.

The app returns when TWS sends the ExecutionsDetailsEndEvent, and if it does not send that event within 5 seconds, you'll get the timeout event https://github.com/amittleider/AutoFinance.Broker/blob/master/AutoFinance.Broker/InteractiveBrokers/Controllers/TwsControllerBase.cs#L273C34-L273C34 . All the other methods like PlaceOrder work the same way -- they wait for a specific event to be fired and then they return https://github.com/amittleider/AutoFinance.Broker/blob/master/AutoFinance.Broker/InteractiveBrokers/Controllers/TwsControllerBase.cs#L661 .

IB has changed their APIs in the past so I wouldn't rule it out as a possibility, but from what I gather, it's working sometimes for you and not work other times. Could you send some more info about how you're using it?

amittleider commented 8 months ago

Actually I'm re-reading your message and you said "Transmit = False" again. Why don't you want to transmit? There are a few specific cases where you would use Transmit = False, and they are all related to placing multiple orders simultaneously.

For example, while placing a bracket order, you set the first 2 orders to Transmit = False and the last order to Transmit = True. Once the order is transmitted, all orders will be placed simultaneously. See https://github.com/amittleider/AutoFinance.Broker/blob/master/AutoFinance.Broker/InteractiveBrokers/Controllers/TwsController.cs#L92 .

The PlaceOrder success callback won't be fired unless you transmit, so it would be normal in that case that your request is getting cancelled after the 5 second timeout.

CoolDixon commented 8 months ago

That's exactly why I was using transmit=false, in order to be able to place a bracket order, but without take profit, only with a stop loss attached. The buy (sell) goes with transmit=false and the final sell (buy) goes with transmit = true. But it used to fail the first request. I was placing both orders sequentially, not in parallel as in the example you point out

But now I receive this nasty taskcaocellationexceptions very often with other operations (I opened the issue asking about transmit=false, but now I have this problem with other commands too in a random manner)

Screenshot 2023-12-18 at 11 31 22

amittleider commented 8 months ago

Can you please provide a code sample? Placing a stop with no take should be possible, just follow the example of the PlaceBracketOrder. Make sure to set the entry order first with Transmit=false (do not await), then set the exit order with Transmit=True (do not await), then run a Task.WaitAll(task1, task2)

CoolDixon commented 8 months ago

In my head the entry should be sent and (not) transmitted before the stop order. With a Task.WaitAll the order can't be warranted, that's why I was doing it in two consecutive orders. But with the WaitAll I still get the same error:

Screenshot 2023-12-18 at 18 44 09

This is my code:

`

        Contract contract = new Contract
        {
            SecType = TwsContractSecType.Stock,
            Symbol = "PEP",
            Exchange = TwsExchange.Smart,
            //PrimaryExch = TwsExchange.Island,
            Currency = TwsCurrency.Usd,
        };

        var orderId = await twsController.GetNextValidIdAsync();
        var orderId2 = await twsController.GetNextValidIdAsync();

        Order entryOrder = new Order()
        {
            Action = TwsOrderActions.Buy,
            OrderType = TwsOrderType.Limit,
            TotalQuantity = 120,
            LmtPrice = 160,
            Tif = TwsTimeInForce.GoodTillClose,
            Transmit = false,
        };

        Order stopOrder = new Order()
        {
            Action =TwsOrderActions.Reverse(entryOrder.Action),
            OrderType = TwsOrderType.StopLoss,
            TotalQuantity = entryOrder.TotalQuantity,
            AuxPrice = 149.99,
            //LmtPrice = 0,
            Tif = TwsTimeInForce.GoodTillClose,
            ParentId = orderId,
            Transmit = true,
        };

        var entryOrderAckTask = twsController.PlaceOrderAsync(orderId, contract, entryOrder);
        var stopOrderAckTask = twsController.PlaceOrderAsync(orderId2, contract, stopOrder);
        Task.WaitAll(entryOrderAckTask, stopOrderAckTask);
        Log.Information($"Placed Orders -> Entry {orderId}: {entryOrderAckTask.Result}. Stop {orderId2}: {stopOrderAckTask.Result}");

`

(The operation cancelled exception is thrown in both the sell and the buy threads)

But then the order is really sent to the broker: IMG_41F3CE647D6A-1