Restrict portfolio greeks to open positions - #4700
Open
folknor wants to merge 1 commit into
Open
Conversation
`GreeksCalculator::portfolio_greeks` bound `cache.positions(...)` to a local named `open_positions`, but that query returns every position, open and closed. A closed position has `signed_qty == 0.0` and so contributes exactly nothing to the aggregate, yet `instrument_greeks` was still called for it and its error propagated - letting a position the portfolio no longer holds fail an entire portfolio snapshot once its price data is gone or its contract has expired. The query now uses `positions_open` with the same filter arguments, which also stops greeks being computed for closed positions and multiplied by zero. Error propagation for positions actually held is unchanged. With `side = PositionSide::Flat` the call previously selected closed positions and returned zero or an error; it now selects nothing and returns zero. Coded by an LLM.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GreeksCalculator::portfolio_greeksdocuments itself as aggregating open positions but queries the full position index.A closed position can abort the whole call
portfolio_greeksbindscache.positions(...)to a local namedopen_positions.Cache::positionsreturns every position, open and closed, whileCache::positions_opensits directly beside it. A closed position hassigned_qty == 0.0, soquantity * &instrument_greekscontributes exactly nothing to the total - butinstrument_greeksis still called for it and its error propagates, so a position the portfolio no longer holds can fail an entire portfolio snapshot once its price data is gone or its contract has expired. The query now usespositions_openwith the same filter arguments, which also stops greeks being computed for closed positions and multiplied by zero.Error propagation for positions actually held is unchanged.
Behaviour change with side = Flat
portfolio_greeks(side = PositionSide::Flat)previously selected closed positions, computed their greeks and returned zero or an error. It now selects nothing and returns zero. An open position cannot be flat under thePositioninvariants, so this removes behaviour that contradicted the method's own contract.NoPositionSide,LongandShortare unaffected.Testing
test_portfolio_greeks_ignores_closed_position_with_missing_priceholds one open option position and one closed futures position whose instrument is registered without a price. The closed position is built the way the engine builds one - opened, offsetting fill applied, thencache.update_position- and the test asserts it satisfiesis_closed()and has left the open index before calling. Against the unfixed query it fails withNo price available for CLOSED.GLBX; with the fix it returns the open position's aggregate.test_portfolio_greeks_preserves_open_position_aggregate_and_side_filterscharacterizes the success path over a long and a short position with non-unit quantities, comparing everyPortfolioGreeksfield against an independently computedsigned_qty * greekssum, asserting those expectations are non-zero first, then repeating for theLongandShortfilters. It passes against the unfixed code by design - a closed position already contributed zero, so the open-book aggregate is unchanged - and the missing-price test is the one that fails without the fix.