Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LIFO/"breakeven" pps for ib #336

Merged
merged 58 commits into from
Jun 29, 2022
Merged

LIFO/"breakeven" pps for ib #336

merged 58 commits into from
Jun 29, 2022

Conversation

goodboy
Copy link
Contributor

@goodboy goodboy commented Jun 7, 2022

Proper attempt at #307 and a local "trades" ledger system using .toml files under <confdir>/ledgers/ where files will be named something like: trades_<brokername>_<accountname>.toml

So far ledger contents looking something like this:

Click to expand!
[ib.20220512.977661167]
accountId = "DUDUDUDUD"
acctAlias = ""
model = ""
currency = "USD"
fxRateToBase = 1.3046
assetCategory = "FUT"
symbol = "MGCM2"
description = "MGC 28JUN22"
conid = 430360671
securityID = ""
securityIDType = ""
cusip = ""
isin = ""
listingExchange = "NYMEX"
underlyingConid = 79702479
underlyingSymbol = "MGC"
underlyingSecurityID = ""
underlyingListingExchange = ""
issuer = ""
multiplier = 10
strike = ""
expiry = 20220628
tradeID = 977661167
putCall = ""
reportDate = 20220512
principalAdjustFactor = ""
dateTime = "20220512;115003"
tradeDate = 20220512
settleDateTarget = 20220513
transactionType = "ExchTrade"
exchange = "NYMEX"
quantity = 1
tradePrice = 1834.3
tradeMoney = 18343
proceeds = -18343
taxes = 0
ibCommission = -0.77
ibCommissionCurrency = "USD"
netCash = -97.77
closePrice = 1824.6
openCloseIndicator = "O"
notes = ""
cost = 18343.77
fifoPnlRealized = 0
fxPnl = 0
mtmPnl = -97
origTradePrice = 0
origTradeDate = ""
origTradeID = ""
origOrderID = 0
clearingFirmID = ""
transactionID = 3896422621
buySell = "BUY"
ibOrderID = 398090454
ibExecID = "0000e1a7.627cece5.01.01"
brokerageOrderID = "00dd230498015d2347c93b9.0001"
orderReference = ""
volatilityOrderLink = ""
exchOrderId = "00d345980012a0234dd49[2]"
extExecID = "237147708B"
orderTime = "20220512;115003"
openDateTime = ""
holdingPeriodDateTime = ""
whenRealized = ""
whenReopened = ""
levelOfDetail = "EXECUTION"
changeInPrice = 0
changeInQuantity = 0
orderType = "LMT"
traderID = ""
isAPIOrder = "Y"
accruedInt = 0
serialNumber = ""
deliveryType = ""
commodityType = ""
fineness = 0.0
weight = "0.0 ()"

And, as of right now pps.toml entries lookin more or less like this (example only):

[ib.algopaper."mnq.globex.20220916"]
size = 58.0
be_price = 11703.458965517251
bsuid = 497954580
expiry = "2022-09-16T00:00:00+00:00"
clears = [
 { tid = "0000e1a7.629f3c2d.01.01", cost = 0.57 },
 { tid = "0000e1a7.629fa5c0.01.01", cost = 0.57 },
 { tid = "0000e1a7.62a0a898.01.01", cost = 0.57 },
 { tid = "0000e1a7.62a0fb24.01.01", cost = 0.57 },
]

REQUIREMENT:


TODO: (oustandings moved to #345)

  • pps.toml local position tracking/summary file
    • manual edits by the user and just have the ledger parser(s) complain on mismatches
    • better format in terms of toml data structures so that it's easier to read the pp set by eye:
    • include each transaction as an array of tables which include id, cost, (date-)timestamp, maybe something else?
      • see below, think this is mostly there as a POC
    • make fields under each pp for a breakeven_price
    • include a lifo_price?
    • make ^ prices all arrays which increment with each new transaction/fill entry
  • pp parsing using LIFO style and since last net zero style reporting
  • appends from session trades capture via Client.trades() method
  • integration with PostionTracker UX on charts

Probably as follow up PR(s): -> See #345 for all deferrals and detailed write up of all these

  • extend this to the kraken ledger parsing and generalize into a top level module?
  • piker ledger subcommand?
  • piker pps subcommand with opens pps.toml in editor/pager?
  • roll our own toml encoder?
    • after much pain and anguish getting the toml encoder to output things sanely, i think it's just worth writing a super fast custom encoder that writes adhoc-ly in the format we want for pps.toml, the reader-writer separation is already what tomli does (the fastest pure py reader soon to land in the stdlib) and and then we can just drop toml outright and worry about getting a general encoder later.
    • support better indentation per broker-account for better readability
  • as per bullets in TODO above, we should support pp liftetime "lines" more or less as super simple FSP style graphics that show the beginning, changes, and end to a given pp such that users can easily see past trades and their state changes on top of historical data
  • add proper paper engine support so that user's can trade their forward testing systems like bosses
  • docs / recommendations for storing all ledger / pps.toml updates in git

@goodboy goodboy added clearing auction and mm tech: EMS, OMS, algo-trading brokers-can-smbz features that suits should provide labels Jun 7, 2022
@goodboy goodboy changed the title Lifo pps for ib FILO pps for ib Jun 7, 2022
@goodboy goodboy changed the title FILO pps for ib LIFO pps for ib Jun 10, 2022
@goodboy goodboy requested review from iamzoltan, guilledk and wygud June 14, 2022 19:01
@goodboy goodboy changed the base branch from master to uppx_slice_fix June 16, 2022 19:56
@goodboy goodboy marked this pull request as ready for review June 16, 2022 20:03
@goodboy
Copy link
Contributor Author

goodboy commented Jun 16, 2022

Marking this ready to get some eyes, but it's still super ib-specific and I want to still finesse a buncha stuff and make follow up issues for a more general solution / API for ledgers.

Base automatically changed from uppx_slice_fix to master June 16, 2022 20:20
@goodboy
Copy link
Contributor Author

goodboy commented Jun 18, 2022

Aight, as of right now pps.toml entries lookin more or less like this (example only):

[ib.algopaper."mnq.globex.20220916"]
size = 58.0
be_price = 11703.458965517251
bsuid = 497954580
expiry = "2022-09-16T00:00:00+00:00"
clears = [
 { tid = "0000e1a7.629f3c2d.01.01", cost = 0.57 },
 { tid = "0000e1a7.629fa5c0.01.01", cost = 0.57 },
 { tid = "0000e1a7.62a0a898.01.01", cost = 0.57 },
 { tid = "0000e1a7.62a0fb24.01.01", cost = 0.57 },
]

includes a table of .clears which is the minimal amount of data parsed from the corresponding backend ledger in order to produce the high level details.

As further refinemen we could probably,

  • add a datetime field the clears table?
  • (will defer) include an array of price histories?
  • show size/price values for each clear?

@goodboy goodboy changed the title LIFO pps for ib LIFO/"breakeven" pps for ib Jun 23, 2022
@goodboy goodboy force-pushed the lifo_pps_ib branch 3 times, most recently from 0311e24 to 800715e Compare June 26, 2022 17:52
goodboy added 9 commits June 28, 2022 10:07
Start a generic "position related" util mod and bring in the `Position`
type from the allocator , convert it to a `msgspec.Struct` and add
a `.lifo_update()` method. Implement a WIP pp parser from a trades
ledger and use the new lifo method to gather position entries.
Since "flex reports" are only available for the current session's trades
the day after, this adds support for also collecting trade execution
records for the current session and writing them to the equivalent
ledger file.

Summary:
- add `trades_to_records()` to handle parsing both flex and API event
  objects into a common record form.
- add `norm_trade_records()` to handle converting ledger entries into
  `TradeRecord` types from the new `piker.pps` mod (coming in next
  commit).
Add a `TradeRecord` struct which holds the minimal field set to build
out position entries. Add `.update_pps()` to convert a set of records
into LIFO position entries, optionally allowing for an update to some
existing pp input set. Add `load_pps_from_ledger()` which does a full
ledger extraction to pp objects, ready for writing a `pps.toml`.
goodboy added 22 commits June 28, 2022 10:07
This makes it possible to refresh a single fqsn-position in one's
`pps.toml` by simply deleting the file entry, in which case, if there is
new trade records passed to `load_pps_from_toml()` via the new
`reload_records` kwarg, then the backend ledger entries matching that
symbol will be filtered and used to recompute a fresh position.

This turns out to be super handy when you have crashes that prevent
a `pps.toml` entry from being updated correctly but where the ledger
does have all the data necessary to calculate a fresh correct entry.
- use `tomli` package for reading since it's the fastest pure python
  reader available apparently.
- add new fields to each pp's clears table: price, size, dt
- make `load_pps_from_toml()`'s `reload_records` a dict that can be
  passed in by the caller and is verbatim used to re-read a ledger and
  filter to the specified symbol set to build out fresh pp objects.
- add a `update_from_ledger: bool` flag to `load_pps_from_toml()`
  to allow forcing a full backend ledger read.
- if a set of trades records is passed into `update_pps_conf()` parse
  out the meta data required to cause a ledger reload as per 2 bullets
  above.
- return active and closed pps in separate by-account maps from
  `update_pps_conf()`.
- drop the `key_by` kwarg.
Before we weren't emitting pp msgs when a position went back to "net
zero" (aka the size is zero) nor when a new one was opened (wasn't
previously loaded from the `pps.toml`). This reworks a bunch of the
incremental update logic as well as ports to the changes in the
`piker.pp` module:

- rename a few of the normalizing helpers to be more explicit.
- drop calling `pp.get_pps()` in the trades dialog task and instead
  create msgs iteratively, per account, by iterating through collected
  position and API trade records and calling instead
  `pp.update_pps_conf()`.
- always from-ledger-update both positions reported from ib's pp sys and
  session api trades detected on ems-trade-dialog startup.
- `update_ledger_from_api_trades()` now does **just** that: only updates
  the trades ledger and returns the transaction set.
- `update_and_audit_msgs()` now only the input list of msgs and properly
  generates new msgs for newly created positions that weren't previously
  loaded from the `pps.toml`.
Gah, was a remaining bug where if you tried to update the pps state with
both new trades and from the ledger you'd do a double add of
transactions that were cleared during a `update_pps()` loop. Instead now
keep all clears in tact until ready to serialize to the `pps.toml` file
in which cases we call a new method `Position.minimize_clears()` which
does the work of only keep clears since the last net-zero size.

Re-implement `update_pps_conf()` update logic as a single pass loop
which does expiry and size checking for closed pps all in one pass thus
allowing us to drop `dump_active()` which was kinda redundant anyway..
@goodboy goodboy merged commit d5bc43e into master Jun 29, 2022
@goodboy goodboy deleted the lifo_pps_ib branch June 29, 2022 14:08
This was referenced Jun 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
brokers-can-smbz features that suits should provide clearing auction and mm tech: EMS, OMS, algo-trading
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant