• C#
  • Java
  • VB
  • C++
  • Python
Contact us
Profit And Loss (P&L)

P&L data in the Account Window

UnRealized and Realized P&L is sent to the API function IBApi.EWrapper.updateAccountValue function after a subscription request is made with IBApi.EClient.reqAccountUpdates. This information corresponds to the data in the TWS Account Window, and has a different source of information, a different update frequency, and different reset schedule than PnL data in the TWS Portfolio Window and associated API functions (below). In particular, the unrealized P&L information shown in the TWS Account Window which is sent to updatePortfolioValue will update either (1) when a trade for that particular instrument occurs or (2) every 3 minutes. The realized P&L data in the TWS Account Window is reset to 0 once per day.

  • It is important to keep in mind that the P&L data shown in the Account Window and Portfolio Window will sometimes differ because there is a different source of information and a different reset schedule.

P&L data in the Portfolio Window

Beginning with API v973.03, requests can be made to receive real time updates about the daily P&L and unrealized P&L for an account, or for individual positions. Financial Advisors can also request P&L figures for 'All' subaccounts, or for a portfolio model. In API v973.05+/TWS v968+ this is further extended to include realized P&L information at the account or individual position level.

These newer P&L API functions demonstrated below return the data which is displayed in the TWS Portfolio Window in current versions of TWS (v963+). As such, the P&L values are calculated based on the reset schedule specified in TWS Global Configuration (by default an instrument-specific reset schedule) and this setting affects values sent to the associated API functions as well. Also in TWS, P&L data from virtual forex positions will be included in the account P&L if and only if the Virtual Fx section of the Account Window is expanded.

  • Note: the P&L functions in Python API are available starting in API v973.06+.

P&L subscription requests for individual positions

Subscribe using the IBApi::EClient::reqPnLSingle function Cannot be used with IBroker accounts configured for on-demand lookup with account = 'All'

  • client.reqPnLSingle(17001, "DUD00029", "", 268084);
  • client.reqPnLSingle(17001, "DUD00029", "", 268084);
  • client.reqPnLSingle(17001, "DUD00029", "", 268084)
  • m_pClient->reqPnLSingle(7002, "DUD00029", "", 268084);
  • 1  self.reqPnLSingle(17002, "DU111519", "", 8314)

Currently updates are returned to IBApi.EWrapper.pnlSingle approximately once per second. *subject to change in the future

  • public void pnlSingle(int reqId, decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value)
    {
    Console.WriteLine("PnL Single. Request Id: {0}, Pos {1}, Daily PnL {2}, Unrealized PnL {3}, Realized PnL: {4}, Value: {5}", reqId, Util.DecimalMaxString(pos), Util.DoubleMaxString(dailyPnL), Util.DoubleMaxString(unrealizedPnL),
    Util.DoubleMaxString(realizedPnL), Util.DoubleMaxString(value));
    }
  • @Override
    public void pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) {
    System.out.println(EWrapperMsgGenerator.pnlSingle(reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value));
    }
  • Public Sub pnlSingle(reqId As Integer, pos As Decimal, dailyPnL As Double, unrealizedPnL As Double, realizedPnL As Double, value As Double) Implements EWrapper.pnlSingle
    Console.WriteLine("PnL Single. Request Id: {0}, pos: {1}, daily PnL: {2}, unrealized PnL: {3}, realized PnL: {4}, value: {5}", reqId, Util.DecimalMaxString(pos),
    Util.DoubleMaxString(dailyPnL), Util.DoubleMaxString(unrealizedPnL), Util.DoubleMaxString(realizedPnL), Util.DoubleMaxString(value))
    End Sub
  • void TestCppClient::pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) {
    printf("PnL Single. ReqId: %d, pos: %s, daily PnL: %s, unrealized PnL: %s, realized PnL: %s, value: %s\n", reqId, DecimalFunctions::decimalStringToDisplay(pos).c_str(), Utils::doubleMaxString(dailyPnL).c_str(),
    Utils::doubleMaxString(unrealizedPnL).c_str(), Utils::doubleMaxString(realizedPnL).c_str(), Utils::doubleMaxString(value).c_str());
    }
  • 1  def pnlSingle(self, reqId: int, pos: Decimal, dailyPnL: float,
    2  unrealizedPnL: float, realizedPnL: float, value: float):
    3  super().pnlSingle(reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value)
    4  print("Daily PnL Single. ReqId:", reqId, "Position:", decimalMaxString(pos),
    5  "DailyPnL:", floatMaxString(dailyPnL), "UnrealizedPnL:", floatMaxString(unrealizedPnL),
    6  "RealizedPnL:", floatMaxString(realizedPnL), "Value:", floatMaxString(value))
  • If a P&L subscription request is made for an invalid conId or contract not in the account, there will not be a response.
  • As elsewhere in the API, a max double value will indicate an 'unset' value. This corresponds to an empty cell in TWS.
  • Introducing broker accounts without a large number of subaccounts (<50) can receive aggregate data by specifying the account as "All".
  • *Cannot be used with IBroker accounts configured for on-demand lookup with account = 'All'

Subscriptions are cancelled using the IBApi::EClient::cancelPnLSingle function:

  • client.cancelPnLSingle(17001);
  • client.cancelPnLSingle(17001);
  • client.cancelPnLSingle(17001)
  • m_pClient->cancelPnLSingle(7002);
  • 1  self.cancelPnLSingle(17002)

P&L subscription requests for accounts

Subscribe using the IBApi::EClient::reqPnL function:

  • client.reqPnL(17001, "DUD00029", "");
  • client.reqPnL(17001, "DUD00029", "");
  • client.reqPnL(17001, "DUD00029", "")
  • m_pClient->reqPnL(7001, "DUD00029", "");
  • 1  self.reqPnL(17001, "DU111519", "")
  • Introducing broker accounts with less than 50 subaccounts can receive aggregate PnL for all subaccounts by specifying 'All' as the account code.
  • With requests for advisor accounts with many subaccounts and/or positions can take several seconds for aggregated P&L to be computed and returned.
  • For account P&L data the TWS setting "Prepare portfolio PnL data when downloading positions" must be checked.

Updates are sent to IBApi.EWrapper.pnl

  • public void pnl(int reqId, double dailyPnL, double unrealizedPnL, double realizedPnL)
    {
    Console.WriteLine("PnL. Request Id: {0}, Daily PnL: {1}, Unrealized PnL: {2}, Realized PnL: {3}", reqId, Util.DoubleMaxString(dailyPnL), Util.DoubleMaxString(unrealizedPnL), Util.DoubleMaxString(realizedPnL));
    }
  • @Override
    public void pnl(int reqId, double dailyPnL, double unrealizedPnL, double realizedPnL) {
    System.out.println(EWrapperMsgGenerator.pnl(reqId, dailyPnL, unrealizedPnL, realizedPnL));
    }
  • Public Sub pnl(reqId As Integer, dailyPnL As Double, unrealizedPnL As Double, realizedPnL As Double) Implements EWrapper.pnl
    Console.WriteLine("PnL. Request Id: {0}, daily PnL: {1}, unrealized PnL: {2}, realized PnL: {3}", reqId, Util.DoubleMaxString(dailyPnL), Util.DoubleMaxString(unrealizedPnL), Util.DoubleMaxString(realizedPnL))
    End Sub
  • void TestCppClient::pnl(int reqId, double dailyPnL, double unrealizedPnL, double realizedPnL) {
    printf("PnL. ReqId: %d, daily PnL: %s, unrealized PnL: %s, realized PnL: %s\n", reqId, Utils::doubleMaxString(dailyPnL).c_str(), Utils::doubleMaxString(unrealizedPnL).c_str(),
    Utils::doubleMaxString(realizedPnL).c_str());
    }
  • 1  def pnl(self, reqId: int, dailyPnL: float,
    2  unrealizedPnL: float, realizedPnL: float):
    3  super().pnl(reqId, dailyPnL, unrealizedPnL, realizedPnL)
    4  print("Daily PnL. ReqId:", reqId, "DailyPnL:", floatMaxString(dailyPnL),
    5  "UnrealizedPnL:", floatMaxString(unrealizedPnL), "RealizedPnL:", floatMaxString(realizedPnL))

Cancel unnecessary subscriptions with the IBApi::EClient::cancelPnL function:

  • client.cancelPnL(17001);
  • client.cancelPnL(17001);
  • client.cancelPnL(17001)
  • m_pClient->cancelPnL(7001);
  • 1  self.cancelPnL(17001)