How to get the positionId using openApiPy?

Created at 23 Feb 2022, 09:19
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!
PR

prenven570

Joined 24.12.2021

How to get the positionId using openApiPy?
23 Feb 2022, 09:19


I need the positionId of the opened position in order to close them with:

sendProtoOAClosePositionReq(positionId, volume, clientMsgId = None)

I tried to print that value doing:

print(request.positionId) inside the sendProtoOAReconcileReq function,

but i get an attribute error. This is part of my code:

 

#I send a market order

def sendProtoOANewOrderReq(results):
        
        
        symbolId = 22395
        volume = 1
        clientMsgId = None
        
        request = ProtoOANewOrderReq()
        request.ctidTraderAccountId = currentAccountId
        request.symbolId = int(symbolId)
        request.orderType = ProtoOAOrderType.MARKET
        request.tradeSide = ProtoOATradeSide.BUY
        request.volume = int(volume) * 100
    
        if request.orderType == ProtoOAOrderType.LIMIT:
            request.limitPrice = float(price)
        elif request.orderType == ProtoOAOrderType.STOP:
            request.stopPrice = float(price)
            
        deferred = client.send(request, clientMsgId = clientMsgId)
        deferred.addErrback(onError)
        
        
        deferred.addCallbacks(sendProtoOAReconcileReq, onError)
        
#I want to get positionId, but I get an attribute error        
def sendProtoOAReconcileReq(result):
    
    clientMsgId = None
    request = ProtoOAReconcileReq()
    request.ctidTraderAccountId = currentAccountId
    
    deferred = client.send(request, clientMsgId = clientMsgId)
    
    deferred.addErrback(onError)
    print(request.positionId)
    


@prenven570
Replies

amusleh
24 Feb 2022, 09:07

Hi,

To get a position ID you can either use ExecutionEvent or Reconcile request.

The reconcile request gives you list of all open account orders with their detail, and ExecutionEvent occurs whenever you perform a trading operation on your account.

In our console sample use setAccount command to authorize a trading account, ex: setAccount account_Id

For example, if I use the console sample, and set account to one of my accounts, and then if I create a new market order I will receive the execution event:

 ctidTraderAccountId: 16608956
executionType: ORDER_FILLED
position {
  positionId: 263362553
  tradeData {
    symbolId: 2
    volume: 100000
    tradeSide: SELL
    openTimestamp: 1645685625147
    guaranteedStopLoss: false
  }
  positionStatus: POSITION_STATUS_OPEN
  swap: 0
  price: 1.34984
  utcLastUpdateTimestamp: 1645685625147
  commission: -4
  marginRate: 1.34984
  mirroringCommission: 0
  guaranteedStopLoss: false
  usedMargin: 270
  moneyDigits: 2
}
order {
  orderId: 399293765
  tradeData {
    symbolId: 2
    volume: 100000
    tradeSide: SELL
    openTimestamp: 1645685624943
    guaranteedStopLoss: false
  }
  orderType: MARKET
  orderStatus: ORDER_STATUS_FILLED
  executionPrice: 1.34984
  executedVolume: 100000
  utcLastUpdateTimestamp: 1645685625147
  closingOrder: false
  clientOrderId: "ctd-df2b5de6032c47609a443bf746b136d0"
  timeInForce: IMMEDIATE_OR_CANCEL
  positionId: 263362553
}
deal {
  dealId: 365614484
  orderId: 399293765
  positionId: 263362553
  volume: 100000
  filledVolume: 100000
  symbolId: 2
  createTimestamp: 1645685624943
  executionTimestamp: 1645685625147
  utcLastUpdateTimestamp: 1645685625147
  executionPrice: 1.34984
  tradeSide: SELL
  dealStatus: FILLED
  marginRate: 1.34984
  commission: -4
  baseToUsdConversionRate: 1.34984
  moneyDigits: 2
}
isServerEvent: false

You see in above execution event, the position ID, order ID and all the other details are there.

You have to authorize your connection to an account, then you will receive the execution event, for getting execution events use the general MessageReceivedCallback:

    def onMessageReceived(client, message): # Callback for receiving all messages
        if message.payloadType in [ProtoOASubscribeSpotsRes().payloadType, ProtoOAAccountLogoutRes().payloadType, ProtoHeartbeatEvent().payloadType]:
            return
        elif message.payloadType == ProtoOAApplicationAuthRes().payloadType:
            print("API Application authorized\n")
            print("Please use setAccount command to set the authorized account before sending any other command, try help for more detail\n")
            print("To get account IDs use ProtoOAGetAccountListByAccessTokenReq command")
            if currentAccountId is not None:
                sendProtoOAAccountAuthReq()
                return
        elif message.payloadType == ProtoOAAccountAuthRes().payloadType:
            protoOAAccountAuthRes = Protobuf.extract(message)
            print(f"Account {protoOAAccountAuthRes.ctidTraderAccountId} has been authorized\n")
            print("This acccount will be used for all future requests\n")
            print("You can change the account by using setAccount command")
        else:
            print("Message received: \n", Protobuf.extract(message))
        reactor.callLater(3, callable=executeUserCommand)

    client.setMessageReceivedCallback(onMessageReceived)

The above code is part of our console sample.

To get orders data with reconcile request you just have to send a reconcile request after account authorization and you will receive back the response:

    def sendProtoOAReconcileReq(clientMsgId = None):
        request = ProtoOAReconcileReq()
        request.ctidTraderAccountId = currentAccountId
        deferred = client.send(request, clientMsgId = clientMsgId)
        deferred.addErrback(onError)

You can use both the deferred or general message received call back for getting back the response.

Here is an example of reconcile response:

Message received:
 ctidTraderAccountId: 16608956
position {
  positionId: 263362553
  tradeData {
    symbolId: 2
    volume: 100000
    tradeSide: SELL
    openTimestamp: 1645685625147
    guaranteedStopLoss: false
  }
  positionStatus: POSITION_STATUS_OPEN
  swap: 0
  price: 1.34984
  utcLastUpdateTimestamp: 1645685625147
  commission: -4
  marginRate: 1.34984
  mirroringCommission: 0
  guaranteedStopLoss: false
  usedMargin: 270
  moneyDigits: 2
}

Now, regarding your issue, there is no position Id on reconcile request, the request is a message you will send for getting positions/orders data.

Please read the Open API documentation, review the console sample code, and play with it, then you will understand how it works.


@amusleh

prenven570
24 Feb 2022, 09:25

RE:

amusleh said:

Hi,

To get a position ID you can either use ExecutionEvent or Reconcile request.

The reconcile request gives you list of all open account orders with their detail, and ExecutionEvent occurs whenever you perform a trading operation on your account.

In our console sample use setAccount command to authorize a trading account, ex: setAccount account_Id

For example, if I use the console sample, and set account to one of my accounts, and then if I create a new market order I will receive the execution event:

 ctidTraderAccountId: 16608956
executionType: ORDER_FILLED
position {
  positionId: 263362553
  tradeData {
    symbolId: 2
    volume: 100000
    tradeSide: SELL
    openTimestamp: 1645685625147
    guaranteedStopLoss: false
  }
  positionStatus: POSITION_STATUS_OPEN
  swap: 0
  price: 1.34984
  utcLastUpdateTimestamp: 1645685625147
  commission: -4
  marginRate: 1.34984
  mirroringCommission: 0
  guaranteedStopLoss: false
  usedMargin: 270
  moneyDigits: 2
}
order {
  orderId: 399293765
  tradeData {
    symbolId: 2
    volume: 100000
    tradeSide: SELL
    openTimestamp: 1645685624943
    guaranteedStopLoss: false
  }
  orderType: MARKET
  orderStatus: ORDER_STATUS_FILLED
  executionPrice: 1.34984
  executedVolume: 100000
  utcLastUpdateTimestamp: 1645685625147
  closingOrder: false
  clientOrderId: "ctd-df2b5de6032c47609a443bf746b136d0"
  timeInForce: IMMEDIATE_OR_CANCEL
  positionId: 263362553
}
deal {
  dealId: 365614484
  orderId: 399293765
  positionId: 263362553
  volume: 100000
  filledVolume: 100000
  symbolId: 2
  createTimestamp: 1645685624943
  executionTimestamp: 1645685625147
  utcLastUpdateTimestamp: 1645685625147
  executionPrice: 1.34984
  tradeSide: SELL
  dealStatus: FILLED
  marginRate: 1.34984
  commission: -4
  baseToUsdConversionRate: 1.34984
  moneyDigits: 2
}
isServerEvent: false

You see in above execution event, the position ID, order ID and all the other details are there.

You have to authorize your connection to an account, then you will receive the execution event, for getting execution events use the general MessageReceivedCallback:

    def onMessageReceived(client, message): # Callback for receiving all messages
        if message.payloadType in [ProtoOASubscribeSpotsRes().payloadType, ProtoOAAccountLogoutRes().payloadType, ProtoHeartbeatEvent().payloadType]:
            return
        elif message.payloadType == ProtoOAApplicationAuthRes().payloadType:
            print("API Application authorized\n")
            print("Please use setAccount command to set the authorized account before sending any other command, try help for more detail\n")
            print("To get account IDs use ProtoOAGetAccountListByAccessTokenReq command")
            if currentAccountId is not None:
                sendProtoOAAccountAuthReq()
                return
        elif message.payloadType == ProtoOAAccountAuthRes().payloadType:
            protoOAAccountAuthRes = Protobuf.extract(message)
            print(f"Account {protoOAAccountAuthRes.ctidTraderAccountId} has been authorized\n")
            print("This acccount will be used for all future requests\n")
            print("You can change the account by using setAccount command")
        else:
            print("Message received: \n", Protobuf.extract(message))
        reactor.callLater(3, callable=executeUserCommand)

    client.setMessageReceivedCallback(onMessageReceived)

The above code is part of our console sample.

To get orders data with reconcile request you just have to send a reconcile request after account authorization and you will receive back the response:

    def sendProtoOAReconcileReq(clientMsgId = None):
        request = ProtoOAReconcileReq()
        request.ctidTraderAccountId = currentAccountId
        deferred = client.send(request, clientMsgId = clientMsgId)
        deferred.addErrback(onError)

You can use both the deferred or general message received call back for getting back the response.

Here is an example of reconcile response:

Message received:
 ctidTraderAccountId: 16608956
position {
  positionId: 263362553
  tradeData {
    symbolId: 2
    volume: 100000
    tradeSide: SELL
    openTimestamp: 1645685625147
    guaranteedStopLoss: false
  }
  positionStatus: POSITION_STATUS_OPEN
  swap: 0
  price: 1.34984
  utcLastUpdateTimestamp: 1645685625147
  commission: -4
  marginRate: 1.34984
  mirroringCommission: 0
  guaranteedStopLoss: false
  usedMargin: 270
  moneyDigits: 2
}

Now, regarding your issue, there is no position Id on reconcile request, the request is a message you will send for getting positions/orders data.

Please read the Open API documentation, review the console sample code, and play with it, then you will understand how it works.

Thanks for your answer. I know that I can see the positionId and other information in the output, but I think I need a way to store the positionId number inside a variable, so I can close the opened position. When I open a position, I'm not able to close it, because "positionId" is not defined, this happens even with a reconcile request. So what can I do to close the opened position?


@prenven570

amusleh
24 Feb 2022, 10:22

Hi,

If you can receive the response then getting the position ID or any other field of it is very easy.

Here is an example:

    def onMessageReceived(client, message): # Callback for receiving all messages
        # execute a trade on your account, to get an execution event
        if message.payloadType == ProtoOAExecutionEvent().payloadType:
            print("Execution event received")
            executionEvent = Protobuf.extract(message)
            print(executionEvent.position.positionId)
        # send a reconcile request to receive a reconcile response
        if message.payloadType == ProtoOAReconcileRes().payloadType:
            print("Reconcile response received")
            reconcileRes = Protobuf.extract(message)
            for position in reconcileRes.position:
                print(position.positionId)
            for order in reconcileRes.order:
                print(order.orderId)

When you receive a message you can check it's payload type, if it's of your interested type then you can serialize the message to that type and access it's data.

In case you used the Twisted deferred for getting a request response you don't have to do the serialization, it will be done automatically and your callback will be called with the request message response, you can't use the Twisted deferreds for events like spot event, execution event, etc... for them you have to use the message received call back.


@amusleh

prenven570
24 Feb 2022, 10:28

RE:

amusleh said:

Hi,

If you can receive the response then getting the position ID or any other field of it is very easy.

Here is an example:

    def onMessageReceived(client, message): # Callback for receiving all messages
        # execute a trade on your account, to get an execution event
        if message.payloadType == ProtoOAExecutionEvent().payloadType:
            print("Execution event received")
            executionEvent = Protobuf.extract(message)
            print(executionEvent.position.positionId)
        # send a reconcile request to receive a reconcile response
        if message.payloadType == ProtoOAReconcileRes().payloadType:
            print("Reconcile response received")
            reconcileRes = Protobuf.extract(message)
            for position in reconcileRes.position:
                print(position.positionId)
            for order in reconcileRes.order:
                print(order.orderId)

When you receive a message you can check it's payload type, if it's of your interested type then you can serialize the message to that type and access it's data.

In case you used the Twisted deferred for getting a request response you don't have to do the serialization, it will be done automatically and your callback will be called with the request message response, you can't use the Twisted deferreds for events like spot event, execution event, etc... for them you have to use the message received call back.

Thanks a lot!!! It worked


@prenven570

tangducbao101
07 Jul 2023, 15:14

RE:

ProtoOAReconcileReq is a good API to check opening positions and orders. 


@tangducbao101