nautechsystems / nautilus_trader

A high-performance algorithmic trading platform and event-driven backtester
https://nautilustrader.io
GNU Lesser General Public License v3.0
1.99k stars 456 forks source link

Account needs enhancing to include detailed margin information #56

Closed scoriiu closed 3 years ago

scoriiu commented 3 years ago

Account should reflect the equity balance at all times. In case there is a position open, account.equity should be something like cash + position_value_unleveraged + unrealized_pnl

cjdsellers commented 3 years ago

Yes, I think this is necessary.

We need to start moving the account towards something more general, it's currently working for FXCM only.

Probably the AccountState event needs overhauling, again lets look into the CCXT account updates.

scoriiu commented 3 years ago

Account update will differ a lot based on the trading type (e.g. derivatives, margin, spot). CCXT doesn't yet take into account these types and returns a poor format IMO. I propose to better look on a account updates via websocket for this types and start from there.

Example bitmex:

{
  "table": "margin",
  "action": "partial",
  "keys": [
    "account"
  ],
  "types": {
    "account": "long",
    "currency": "symbol",
    "riskLimit": "long",
    "prevState": "symbol",
    "state": "symbol",
    "action": "symbol",
    "amount": "long",
    "pendingCredit": "long",
    "pendingDebit": "long",
    "confirmedDebit": "long",
    "prevRealisedPnl": "long",
    "prevUnrealisedPnl": "long",
    "grossComm": "long",
    "grossOpenCost": "long",
    "grossOpenPremium": "long",
    "grossExecCost": "long",
    "grossMarkValue": "long",
    "riskValue": "long",
    "taxableMargin": "long",
    "initMargin": "long",
    "maintMargin": "long",
    "sessionMargin": "long",
    "targetExcessMargin": "long",
    "varMargin": "long",
    "realisedPnl": "long",
    "unrealisedPnl": "long",
    "indicativeTax": "long",
    "unrealisedProfit": "long",
    "syntheticMargin": "long",
    "walletBalance": "long",
    "marginBalance": "long",
    "marginBalancePcnt": "float",
    "marginLeverage": "float",
    "marginUsedPcnt": "float",
    "excessMargin": "long",
    "excessMarginPcnt": "float",
    "availableMargin": "long",
    "withdrawableMargin": "long",
    "timestamp": "timestamp",
    "grossLastValue": "long",
    "commission": "float"
  },
  "foreignKeys": {

  },
  "attributes": {
    "account": "sorted"
  },
  "filter": {
    "account": 1513111
  },
  "data": [
    {
      "account": 1513111,
      "currency": "XBt",
      "riskLimit": 1000000000000,
      "prevState": "",
      "state": "",
      "action": "",
      "amount": 9760950,
      "pendingCredit": 0,
      "pendingDebit": 0,
      "confirmedDebit": 0,
      "prevRealisedPnl": 224002,
      "prevUnrealisedPnl": 0,
      "grossComm": 0,
      "grossOpenCost": 0,
      "grossOpenPremium": 0,
      "grossExecCost": 0,
      "grossMarkValue": 0,
      "riskValue": 0,
      "taxableMargin": 0,
      "initMargin": 0,
      "maintMargin": 0,
      "sessionMargin": 0,
      "targetExcessMargin": 0,
      "varMargin": 0,
      "realisedPnl": 0,
      "unrealisedPnl": 0,
      "indicativeTax": 0,
      "unrealisedProfit": 0,
      "syntheticMargin": null,
      "walletBalance": 9760950,
      "marginBalance": 9760950,
      "marginBalancePcnt": 1,
      "marginLeverage": 0,
      "marginUsedPcnt": 0,
      "excessMargin": 9760950,
      "excessMarginPcnt": 1,
      "availableMargin": 9760950,
      "withdrawableMargin": 9760950,
      "timestamp": "2020-07-11T12:15:15.470Z",
      "grossLastValue": 0,
      "commission": null
    }
  ]
}
scoriiu commented 3 years ago

Also, giving the option to simulate with leverage would be very useful, but this should be a separate thread.

cjdsellers commented 3 years ago

Agreed. Opened an issue for simulating margin and leverage #57.

cjdsellers commented 3 years ago

So I think we should start as simple as possible to achieve some basic functionality and extend from there. I think using BitMEX as a template is a good starting point although I'll also be referring to Binance and other API's. Definitely not every field has to be included or is even available everywhere.

For the current AccountState event I think the following properties are redundant and/or can be tracked elsewhere.

cash_start_day cash_activity_day margin_ratio margin_call_status

We have to decide a sensible amount of margin information reporting, so it can be both simulated in a backtest, and considered for risk controls in live trading.

scoriiu commented 3 years ago

I agree. Starting with the basics is a good idea. For the first phase I would propose to ignore the margin related information and have some basic properties like cash and equity.

cjdsellers commented 3 years ago

Once the position id issue is fixed I'll refactor Account to constantly calculate the available equity.

I'll have a closer look at account fields being returned from other APIs and generalize the AccountState event.

It may take us a few goes to get to where we need to though.

scoriiu commented 3 years ago

Sounds great!

cjdsellers commented 3 years ago

You could have a go at refactoring Account so that equity becomes a readonly property in the account.pxd, which is updated every time there's an account state event.

Then that method will be redundant, there's only a few call sites to equity in the codebase I think.

Up to you?

From reading the BitMEX docs today I think there's going to be a growing assortment of metrics being tracked in account.

scoriiu commented 3 years ago

Shouldn't it be updated on each tick? This is because the unrealized PNL changes from tick to tick. So the account.equity would then be account.available_balance + position.quantity (unlevereged when leverage will be supported ) + position.unrealized_pnl

scoriiu commented 3 years ago

Bitmex represents wallet with 3 properties: wallet_balance = deposits - withdrawals + realized_pnl margin_balance = wallet_balance + unrealized_pnl available_balance = margin_balance - order.margin - position.margin

I suggest using the same format and drop cash_balance, cash_start_day, cash_activity_day, free_equity.

cjdsellers commented 3 years ago

Shouldn't it be updated on each tick? This is because the unrealized PNL changes from tick to tick. So the account.equity would then be account.available_balance + position.quantity (unlevereged when leverage will be supported ) + position.unrealized_pnl

You're right Account will need to receive QuoteTicks for any assets its holding so that unrealized data can be generated. I can just add a simple handler method, and automatically send relevant quote ticks to it from the DataEngine before any strategies. I'm still getting my head around how BitMEX handles the leveraging so it may need other data such as Mark and Fair price, unsure at the moment.

scoriiu commented 3 years ago

I suggest for the first phase going with the simplest leveraging mechanics operating based on the QuoteTick pricing info and a leverage variable. Also having a warning in the code if leverage is configured, saying that liquidation functionality is not yet available. Later we can add more complex logic for liquidations operating based on the Mark and Index pricing info.

cjdsellers commented 3 years ago

I've been thinking about how to set this up and it may be cleaner and more appropriate to have the Portfolio provide the realized and unrealized PNL as it holds a reference to all of the positions (which in turn provide their own PNLs). It would work in conjunction with Account to determine available equity and margins.

It could even subscribe to and unsubscribe from the quote ticks it requires to calculate unrealized PNL based on which symbol positions are currently open. I'll do some more thinking and see what comes out when I start coding it.

Regarding the leverage I agree a simple property with a warning if set above 1, we can mature the feature as live trading capability gets closer.

I also note the need to track order margin.

scoriiu commented 3 years ago

Sounds good. I haven't really looked into the Portfolio logic yet. So will both Account and Portfolio track the total margin of the account then? Who will in this case track the available balance (which is wallet_balance - position_margin - working_orders_margin)?

cjdsellers commented 3 years ago

Account and AccountState have now been stripped back in preparation for the redesign.

I'm flagging that whilst BitMEX is being heavily referenced as a model, the platform must remain as general as possible to continue working for other exchanges/brokers and asset classes.

cjdsellers commented 3 years ago

The AccountInquiry command has been removed for simplicity (was an artifact from FIX4.4 and applicable there only). The user/system should not be responsible for manually requesting account information, this will be handled inside individual connected ExecutionClients, ensuring that Account states are always consistent and up to date.

cjdsellers commented 3 years ago

Portfolio has been stripped back and wired into the system more effectively - ready for the new design. Accounts are now registered with the Portfolio as they come online which will help with all kinds of PNL and margin calculations depending on where we decide the responsibility lies.

cjdsellers commented 3 years ago

This thread seems to be converging with #57