-
Notifications
You must be signed in to change notification settings - Fork 23
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
Feat/track pnl #966
Feat/track pnl #966
Conversation
Note: I should probably extend the e2e tests with asserts that the position is actually |
Note: It would potentially be better to change the |
ALTER TABLE | ||
positions | ||
ADD | ||
COLUMN "temporary_contract_id" TEXT NOT NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could actually be UNIQUE
... CC @luckysori
-- In order to allow re-running this migration we thus have to make sure to only add the value if it does not exist yet. | ||
ALTER TYPE "PositionState_Type" | ||
ADD | ||
VALUE IF NOT EXISTS 'Closed'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel good state
let positions = positions | ||
.into_iter() | ||
.filter(|p| { | ||
p.position_state == PositionState::Open | ||
&& OffsetDateTime::now_utc().ge(&p.expiry_timestamp) | ||
}) | ||
.collect::<Vec<Position>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
positions
should already contain onlyopen
positions.- it might be more efficient to include the
expiry
check in the sql query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I completely agree, but I would clean this up in a follow up. in this PR I just moved the code because I found having this code inline in main quite horrible for readability :)
coordinator/src/db/positions.rs
Outdated
@@ -67,6 +67,26 @@ impl Position { | |||
Ok(positions) | |||
} | |||
|
|||
#[autometrics] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need autometrics
for this call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy paste... we have this on all the functions inside of this Node
impl block at the moment. I'm happy to remove it (or add it to the function below as well where I did not add it 😅)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering how this will look like once we support position resizing 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is good to merge, I left a couple of non-blocking remarks that you might want to address.
But before releasing that to production I guess we will need a migration script for existing positions without a temporary_contract_id
coordinator/migrations/2023-07-19-055140_associate_position_with_dlc/up.sql
Outdated
Show resolved
Hide resolved
ALTER TYPE "PositionState_Type" | ||
ADD | ||
VALUE IF NOT EXISTS 'Closed'; | ||
ALTER TABLE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙃 Maybe not 100% related to your change, but it would be great if we'd also save the closing price on the position and not just the pnl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will see to add the closing price in a follow up, see #967 (comment)
PositionState::Open => crate::position::models::PositionState::Open, | ||
PositionState::Closing => crate::position::models::PositionState::Closing, | ||
PositionState::Closed => crate::position::models::PositionState::Closed { | ||
pnl: realized_pnl.expect("realized pnl to be set when position is closed"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Not sure if I like putting the pnl into the enum. Why not simply keep it as option on the position itself? I think that would also make the transformation from and to the database easier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me this is more idiomatic in rust code. This makes it clear that this pnl
is only there in Closed
state. I think this is more accurate for the model in the business logic. The database cannot easily depict that so I flattened it out in the db. But that's an implementation detail for me :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this is exactly what you want from Rust.
let node = node.clone(); | ||
async move { | ||
loop { | ||
tokio::time::sleep(CLOSED_POSITION_SYNC_INTERVAL).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Whats the rule of when to put an interval setting into the config file and when static on top? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
huh, I did not think about putting it into the config file. My rule of thumb would be: if we think we want to configure it we configure it. Is this relevant for the tests? If so then I'd add it to the config file so we can potentially use shorter intervals for the tests 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we need it in the config I'll address it in a follow up!
.context("Failed to load open and closing positions")?; | ||
|
||
for position in open_and_closing_positions { | ||
let contract = match node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 do we need a similar check for open contracts? I think there are scenarios where we also move backwards. cc @luckysori
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If needed please ping and I'll address it in a follow up!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we could generalise this function to look at also consider the possibility that closing positions could go back to open. I don't think it's currently possible to go backwards in the protocol, but we did talk about it in p2pderivatives/rust-dlc#120.
Is this what you are referring to, @holzeis?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that was what I was referring, thanks for adding the ticket 🙂
{ | ||
Ok(Some(closed_contract)) => closed_contract, | ||
Ok(None) => { | ||
tracing::trace!(position_id=%position.id, "Position not closed yet, skipping"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔧 we might want to add a timeout here and set the position to failed if its still in closing. No need to repeat that sync if the position is in closing for days.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this feature might be good to have, but I think this should be solved outside of this PR.
I captured #969 - feel free to add more information there!
That would require an in-code migration - but I'm questioning if it's even possible to deterministically know which position belongs to which contract so far. Is it worth investing time into this? I propose:
This is simpler, and - at least in my opinion - this tiny amount of pnl we lost/won so far should not matter 😅 |
TLDR; I don't think this model requires changes to introduce resizing :) A few more thoughts - might be good food for thoughts for later :) In my mind the position is always an aggregate over contracts. Orders define the execution that will lead to a contract (or resize of a contract or no contract anymore). One thing that is still missing is associating Below are a few thoughts that discuss how the model could be change. I mostly talk about changing it in the database - the business logic model could be changed as well, but does not have to :) I think we could model the position as a purely virtual aggregate in code (without depicting the position in the database); the position would then be an aggregate of it's orders, and the orders would store more information (e.g. execution price, ...). The position would then not exist in the database, but in order to decide if there is a position (i.e. the position quantity is not We could also do an in-between and delete the position in the database if it does not exist instead of setting it to We could also opt to depict the aggregate differently in the database; at the moment we go for a per user per "cycle" model (where a cycle is basically a contract at the moment). This has the advantage that we can drive the position from the contract state easily. |
bors r+ |
966: Feat/track pnl r=da-kami a=da-kami Especially the first commit will be interesting for everybody to see - we are finally associating the `positions` with the contracts - Thanks for the great pairing session `@luckysori` :) note: This PR only handles the realized pnl, I will see to add tracking for the unrealized pnl in a follow up. related ticket: #932 (I'll add the *fixes* to the follow up :) Co-authored-by: Daniel Karzel <daniel@comit.network>
bors r- |
Canceled. |
Co-authored-by: Lucas Soriano del Pino <lucas_soriano@fastmail.com>
bors r+ |
Build succeeded! The publicly hosted instance of bors-ng is deprecated and will go away soon. If you want to self-host your own instance, instructions are here. If you want to switch to GitHub's built-in merge queue, visit their help page.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Especially the first commit will be interesting for everybody to see - we are finally associating the
positions
with the contracts - Thanks for the great pairing session @luckysori :)note: This PR only handles the realized pnl, I will see to add tracking for the unrealized pnl in a follow up.
related ticket: #932
(I'll add the fixes to the follow up :)