Calculate profit and loss Calculating P&L is an essential use case that needs to be implemented by nearly every cTrader Open API application and service.
Manually calculating P&L is a difficult process as the calculation needs to account for the position size and the possible conversion between the quote asset of the bought or sold symbol and the account deposit currency.
Fortunately, you can simply ask the cTrader backend to calculate P&L for you by sending the ProtoOAGetPositionUnrealizedPnLReq message . You should receive the ProtoOAGetPositionUnrealizedPnLRes message containing the ProtoOAPositionUnrealizedPnL model message in one of its fields.
Note
ProtoOAGetPositionUnrealizedPnLRes contains information about the P&Ls of all currently open positions of the account with the specified ctidTraderAccountId in its repeated positionUnrealizedPnL field.
Rate limits
Requesting P&L is a non-historical request, meaning that you can only perform a maximum of 50 such requests per second. We recommend refreshing P&L once every two to three seconds so that there is no risk of exceeding rate limits.
Learn more about sending and receiving messages in tutorials on Protobuf and JSON .
When operating with Protobuf, you could use the classes generated by the compiler for serialising and deserialising the message for attaining P&L rates. When operating with JSON, you would need to create such classes yourself. Here is an example of how they could look.
C# Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public abstract class OpenAPIModelMessageBase { }
public class PositionUnrealizedPnL : OpenAPIModelMessageBase
{
public PositionUnrealizedPnL () { }
public PositionUnrealizedPnL ( int positionId , int grossUnrealizedPnL , int netUnrealizedPnL )
{
this . PositionId = positionId ;
this . GrossUnrealizedPnL = grossUnrealizedPnL ;
this . NetUnrealizedPnL = netUnrealizedPnL ;
}
public int PositionId { get ; set ; }
public int GrossUnrealizedPnL { get ; set ; }
public int NetUnrealizedPnL { get ; set ; }
}
public class GetPositionUnrealizedPnLReq : OpenAPIMessageBase
{
public GetPositionUnrealizedPnLReq () { }
public GetPositionUnrealizedPnLReq ( int ctidTraderAccountId )
{
this . Payload = new GetPositionUnrealizedPnLReqPayload ( ctidTraderAccountId );
this . ClientMsgId = Guid . NewGuid (). ToString ();
}
public override int PayloadType => 2187 ;
public GetPositionUnrealizedPnLReqPayload ? Payload { get ; set ; }
}
public class GetPositionUnrealizedPnLReqPayload : OpenAPIMessagePayloadBase
{
public GetPositionUnrealizedPnLReqPayload () { }
public GetPositionUnrealizedPnLReqPayload ( int ctidTraderAccountId )
{
this . CtidTraderAccountId = ctidTraderAccountId ;
}
public int CtidTraderAccountId { get ; set ; } = 0 ;
}
public class GetPositionUnrealizedPnLRes : OpenAPIMessageBase
{
public GetPositionUnrealizedPnLRes () { }
public GetPositionUnrealizedPnLRes ( int ctidTraderAccountId , int moneyDigits , List < PositionUnrealizedPnL > positionUnrealizedPnL )
{
this . Payload = new GetPositionUnrealizedPnLResPayload ( ctidTraderAccountId , moneyDigits , positionUnrealizedPnL );
this . ClientMsgId = Guid . NewGuid (). ToString ();
}
public override int PayloadType => 2188 ;
public GetPositionUnrealizedPnLResPayload ? Payload { get ; set ; }
}
public class GetPositionUnrealizedPnLResPayload : OpenAPIMessagePayloadBase
{
public GetPositionUnrealizedPnLResPayload () { }
public GetPositionUnrealizedPnLResPayload ( int ctidTraderAccountId , int moneyDigits , List < PositionUnrealizedPnL > positionUnrealizedPnL )
{
this . CtidTraderAccountId = ctidTraderAccountId ;
this . MoneyDigits = moneyDigits ;
this . PositionUnrealizedPnL = positionUnrealizedPnL ;
}
public int CtidTraderAccountId { get ; set ; } = 0 ;
public int MoneyDigits { get ; set ; } = 0 ;
public List < PositionUnrealizedPnL > PositionUnrealizedPnL { get ; set ; } = new List < PositionUnrealizedPnL > ();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 class OpenAPIModelMessage :
def __init__ ( self ):
pass
class PositionUnrealizedPnL ( OpenAPIModelMessage ):
def __init__ ( self , position_id , gross_unrealized_pnl , net_unrealized_pnl ):
self . position_id = position_id
self . gross_unrealized_pnl = gross_unrealized_pnl
self . net_unrealized_pnl = net_unrealized_pnl
class GetPositionUnrealizedPnLReq ( OpenAPIMessage ):
def __init__ ( self , ctid_trader_account_id , client_msg_id = str ( uuid . uuid4 ())):
self . ctid_trader_account_id = ctid_trader_account_id
self . payload_type = 2187
self . client_msg_id = client_msg_id
self . payload = { "ctidTraderAccountId" : self . ctid_trader_account_id }
def as_json_string ( self ):
return json . dumps ({ "clientMsgId" : self . client_msg_id , "payloadType" : self . payload_type , "payload" : self . payload })
@staticmethod
def from_json ( json_dct ):
return GetPositionUnrealizedPnLReq ( client_id = json_dct [ 'payload' ][ 'clientId' ], client_secret = json_dct [ 'payload' ][ 'clientSecret' ], client_msg_id = json_dct [ 'clientMsgId' ])
class GetPositionUnrealizedPnLRes ( OpenAPIMessage ):
def __init__ ( self , ctid_trader_account_id , position_unrealized_pnl , money_digits , client_msg_id ):
self . ctid_trader_account_id = ctid_trader_account_id
self . position_unrealized_pnl = position_unrealized_pnl
self . money_digits = money_digits
self . client_msg_id = client_msg_id
def as_json_string ( self ):
return json . dumps ({ "clientMsgId" : self . client_msg_id , "payloadType" : self . payload_type , "payload" : self . payload })
@staticmethod
def from_json ( json_dct ):
return GetPositionUnrealizedPnLRes ( ctid_trader_account_id = json_dct [ 'payload' ][ 'clientSecret' ], position_unrealized_pnl = json_dct [ 'payload' ][ 'positionUnrealizedPnL' ], money_digits = json_dct [ 'payload' ][ 'moneyDigits' ], client_msg_id = [ 'clientMsgId' ])