margin update - #151
Conversation
| return false; | ||
| } | ||
|
|
||
| private void checkAndLiquidateAllPositions(OrderCommand cmd) { |
There was a problem hiding this comment.
i assume this is going to be called after every price tick that is different than previous tick... you can clearly see why margin support kills performance of most exchanges, still you can get away with this for some time until you have large enough user base or active enough market to choke the core down...
There was a problem hiding this comment.
In fact, according to the design of exchange-core, there will be an L2 market data inserted into the orderCommand every 10ms. We can use this as a basis
There was a problem hiding this comment.
Can you point where in the code you see that? that looks more like a timer logic ,so that core has something to process at least every 10 ms, thats how you do concept of time in deterministic systems, you make sure some event with timestamp is issued frequently enough for your logic to process things... You cant do system.millis or nanos thats not deterministic. Matching engine shouldnt grab some L2 market data, it is the one issuing it.
There was a problem hiding this comment.
In MatchingEngineRouter#L264, will fetch L2 market data when cmd.serviceFlags !=0, and In GroupingProcessor#L240 will at the end set cmd.serviceFlags to 1 every 10ms.
so our original idea is to reuse this mechanism to trigger liquidation check, but now we don't need to do that.
| if (position.isEmpty()) { | ||
| removePositionRecord(position, userProfile); | ||
| } | ||
| log.debug("Liquidated: uid={} symbol={} size={} price={} pnl={}", userProfile.uid, position.symbol, sizeToLiquidate, price, |
There was a problem hiding this comment.
Someone being liquidated should mean appropriate market orders are issued to reduce their exposure to 0 asap... maybe i need to check out the code in the ide but since i do not see something similar to issuing new OrderCommands i assume you dont do it... you cant just liquidate someone by changing some numbers in internal state. Market order must go out, match with some other one or more orders and then it can be called "liquidated such and such"
There was a problem hiding this comment.
you're right, I was just following the post process in place order, like the updatePositionForMarginTrade function...
I'll try to emit an opposite place order cmd(should marked as type liquidated? so that it has highest priorty), and re-submit to exchange-api.
There was a problem hiding this comment.
yes something like that, you need to use your own core as a customer, usually this liquidation logic and risk calculations are separate to the core because its insanely more compute than what core does, risk follows what each position is going trough, marks most risky ones and as soon as they cross some safety tresholds starts issuing market orders on behalf of that customer to the core, which executes them (core shouldnt care or know which orders are for what) its sole purpose is to match them asap... you can see how much trouble exchange core dev went trough to save few object allocations here and there, all that unreadable code is just to be fast.
So i would discourage putting any stream api or any object allocating logic in there, it usually belongs in a separate process.
|
|
||
| private void checkAndLiquidateAllPositions(OrderCommand cmd) { | ||
| userProfileService.getAllUserProfiles() | ||
| .filter(up -> uidForThisHandler(up.uid)) |
There was a problem hiding this comment.
is this entire method just checking for one user or all? if its one user then its definitely really bad idea to iterate over alll users just to filter one... this should be done with O(1) operation... i cant see implementation of uidForThisHandler but its poorly named, it must return a boolean since its in the filter but from the name i have 0 idea what it actually does...
There was a problem hiding this comment.
all user, every market data change,may be cause use liquidate
There was a problem hiding this comment.
ok then fundamentally its correct but i think its obvious that performance will be shit )
no one does this in the same process as matching, but as proof of concept you can prototype here and then worry how to make it work with external process on a separate core..
| .filter(up -> uidForThisHandler(up.uid)) | ||
| .filter(up -> !up.positions.isEmpty()) | ||
| .forEach(userProfile -> { | ||
| userProfile.positions.stream().forEach(position -> { |
There was a problem hiding this comment.
forget using stream api in performance critical code like this, you are creating a load of objects... all that disruptor magic to avoid object allocation means nothing if you do things like this in critical path
|
changes since last review: @balayanv appreciate your review on this version, thanks! |
changes:
1.in
handleMatcherEventMargin, split updatePositionForMarginTrade into 2 function, for calculate pnl in partial close2.in
BALANCE_ADJUSTMENTcase, check the lockedMargin3.add
checkAndLiquidateAllPositions