Skip to content

Commit

Permalink
chore(coordinator): Add trader_pnl to trade_params table
Browse files Browse the repository at this point in the history
Instead of allowing to insert trades early into the database (via the
`is_complete` column, which is now gone).
  • Loading branch information
luckysori committed Apr 10, 2024
1 parent 03cf117 commit 4887e94
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE trades
ADD COLUMN is_complete BOOLEAN NOT NULL DEFAULT true;

ALTER TABLE trade_params
DROP COLUMN IF EXISTS trader_pnl_sat;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE trades
DROP COLUMN IF EXISTS "is_complete";

ALTER TABLE trade_params
ADD COLUMN trader_pnl_sat BIGINT;
3 changes: 3 additions & 0 deletions coordinator/src/db/trade_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::orderbook::db::custom_types::Direction;
use crate::schema::trade_params;
use bitcoin::secp256k1::PublicKey;
use bitcoin::Amount;
use bitcoin::SignedAmount;
use diesel::ExpressionMethods;
use diesel::PgConnection;
use diesel::QueryDsl;
Expand All @@ -25,6 +26,7 @@ pub(crate) struct TradeParams {
pub average_price: f32,
pub direction: Direction,
pub matching_fee: i64,
pub trader_pnl: Option<i64>,
}

pub(crate) fn insert(
Expand Down Expand Up @@ -71,6 +73,7 @@ impl From<TradeParams> for dlc_protocol::TradeParams {
average_price: value.average_price,
direction: trade::Direction::from(value.direction),
matching_fee: Amount::from_sat(value.matching_fee as u64),
trader_pnl: value.trader_pnl.map(SignedAmount::from_sat),
}
}
}
24 changes: 0 additions & 24 deletions coordinator/src/db/trades.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ struct Trade {
timestamp: OffsetDateTime,
order_matching_fee_sat: i64,
trader_realized_pnl_sat: Option<i64>,
is_complete: bool,
}

#[derive(Insertable, Debug, Clone)]
Expand All @@ -37,7 +36,6 @@ struct NewTrade {
average_price: f32,
order_matching_fee_sat: i64,
trader_realized_pnl_sat: Option<i64>,
is_complete: bool,
}

pub fn insert(
Expand All @@ -51,26 +49,6 @@ pub fn insert(
Ok(trade.into())
}

pub fn mark_as_completed(conn: &mut PgConnection, position_id: i32) -> QueryResult<()> {
let trade = trades::table
.filter(trades::position_id.eq(position_id))
.order_by(trades::id.desc())
.first::<Trade>(conn)
.optional()?
.ok_or(diesel::result::Error::NotFound)?;

let affected_rows = diesel::update(trades::table)
.filter(trades::id.eq(trade.id))
.set(trades::is_complete.eq(true))
.execute(conn)?;

if affected_rows == 0 {
return Err(diesel::result::Error::NotFound);
}

Ok(())
}

pub fn get_latest_for_position(
conn: &mut PgConnection,
position_id: i32,
Expand Down Expand Up @@ -112,7 +90,6 @@ impl From<crate::trade::models::NewTrade> for NewTrade {
average_price: value.average_price,
order_matching_fee_sat: value.order_matching_fee.to_sat() as i64,
trader_realized_pnl_sat: value.trader_realized_pnl_sat,
is_complete: value.is_complete,
}
}
}
Expand All @@ -132,7 +109,6 @@ impl From<Trade> for crate::trade::models::Trade {
timestamp: value.timestamp,
order_matching_fee: Amount::from_sat(value.order_matching_fee_sat as u64),
trader_realized_pnl_sat: value.trader_realized_pnl_sat,
is_complete: value.is_complete,
}
}
}
79 changes: 46 additions & 33 deletions coordinator/src/dlc_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use anyhow::Context;
use anyhow::Result;
use bitcoin::secp256k1::PublicKey;
use bitcoin::Amount;
use bitcoin::SignedAmount;
use diesel::r2d2::ConnectionManager;
use diesel::r2d2::Pool;
use diesel::result::Error::RollbackTransaction;
Expand Down Expand Up @@ -119,10 +120,15 @@ pub struct TradeParams {
pub average_price: f32,
pub direction: Direction,
pub matching_fee: Amount,
pub trader_pnl: Option<SignedAmount>,
}

impl From<(ProtocolId, &commons::TradeParams)> for TradeParams {
fn from((protocol_id, trade_params): (ProtocolId, &commons::TradeParams)) -> Self {
impl TradeParams {
fn new(
trade_params: &commons::TradeParams,
protocol_id: ProtocolId,
trader_pnl: Option<SignedAmount>,
) -> Self {
Self {
protocol_id,
trader: trade_params.pubkey,
Expand All @@ -131,9 +137,10 @@ impl From<(ProtocolId, &commons::TradeParams)> for TradeParams {
average_price: trade_params
.average_execution_price()
.to_f32()
.expect("to fit into f32"),
.expect("to fit"),
direction: trade_params.direction,
matching_fee: trade_params.order_matching_fee(),
trader_pnl,
}
}
}
Expand All @@ -154,6 +161,30 @@ pub enum DlcProtocolType {
Rollover { trader: PublicKey },
}

impl DlcProtocolType {
pub fn open(trade_params: &commons::TradeParams, protocol_id: ProtocolId) -> Self {
Self::Open {
trade_params: TradeParams::new(trade_params, protocol_id, None),
}
}

pub fn renew(
trade_params: &commons::TradeParams,
protocol_id: ProtocolId,
trader_pnl: Option<SignedAmount>,
) -> Self {
Self::Renew {
trade_params: TradeParams::new(trade_params, protocol_id, trader_pnl),
}
}

pub fn settle(trade_params: &commons::TradeParams, protocol_id: ProtocolId) -> Self {
Self::Settle {
trade_params: TradeParams::new(trade_params, protocol_id, None),
}
}
}

impl DlcProtocolType {
pub fn get_trader_pubkey(&self) -> &PublicKey {
match self {
Expand Down Expand Up @@ -403,7 +434,6 @@ impl DlcProtocolExecutor {
average_price: trade_params.average_price,
order_matching_fee,
trader_realized_pnl_sat: Some(trader_realized_pnl_sat),
is_complete: true,
};

db::trades::insert(conn, new_trade)?;
Expand Down Expand Up @@ -433,14 +463,6 @@ impl DlcProtocolExecutor {
channel_id,
)?;

let original = db::positions::Position::get_position_by_trader(
conn,
trade_params.trader,
vec![PositionState::Proposed, PositionState::Resizing],
)?
.context("Can't finish open or resize protocol without position")
.map_err(|_| RollbackTransaction)?;

// TODO(holzeis): We are still updating the position based on the position state. This
// will change once we only have a single position per user and representing
// the position only as view on multiple trades.
Expand All @@ -453,29 +475,20 @@ impl DlcProtocolExecutor {

let order_matching_fee = trade_params.matching_fee;

if matches!(original.position_state, PositionState::Resizing) {
// A resizing protocol may generate PNL, but here we are not able to calculate it, so
// the `Trade` has to be inserted before it is complete. So here we just have to mark
// the `Trade` as complete.

db::trades::mark_as_completed(conn, position.id)?;
} else {
let new_trade = NewTrade {
position_id: position.id,
contract_symbol: position.contract_symbol,
trader_pubkey: trade_params.trader,
quantity: trade_params.quantity,
trader_leverage: trade_params.leverage,
trader_direction: trade_params.direction,
average_price: trade_params.average_price,
order_matching_fee,
trader_realized_pnl_sat: None,
is_complete: true,
};

db::trades::insert(conn, new_trade)?;
let new_trade = NewTrade {
position_id: position.id,
contract_symbol: position.contract_symbol,
trader_pubkey: trade_params.trader,
quantity: trade_params.quantity,
trader_leverage: trade_params.leverage,
trader_direction: trade_params.direction,
average_price: trade_params.average_price,
order_matching_fee,
trader_realized_pnl_sat: trade_params.trader_pnl.map(|pnl| pnl.to_sat()),
};

db::trades::insert(conn, new_trade)?;

Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion coordinator/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ diesel::table! {
average_price -> Float4,
direction -> DirectionType,
matching_fee -> Int8,
trader_pnl_sat -> Nullable<Int8>,
}
}

Expand All @@ -436,7 +437,6 @@ diesel::table! {
timestamp -> Timestamptz,
order_matching_fee_sat -> Int8,
trader_realized_pnl_sat -> Nullable<Int8>,
is_complete -> Bool,
}
}

Expand Down
17 changes: 4 additions & 13 deletions coordinator/src/trade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,9 +374,7 @@ impl TradeExecutor {
None,
&temporary_contract_id,
&temporary_channel_id,
DlcProtocolType::Open {
trade_params: (protocol_id, trade_params).into(),
},
DlcProtocolType::open(trade_params, protocol_id),
)?;

// After the DLC channel has been proposed the position can be created. This fixes
Expand Down Expand Up @@ -550,9 +548,7 @@ impl TradeExecutor {
previous_id,
&temporary_contract_id,
&channel.get_id(),
DlcProtocolType::Renew {
trade_params: (protocol_id, trade_params).into(),
},
DlcProtocolType::renew(trade_params, protocol_id, None),
)?;

// TODO(holzeis): The position should only get created after the dlc protocol has finished
Expand Down Expand Up @@ -720,9 +716,7 @@ impl TradeExecutor {
previous_id,
&temporary_contract_id,
&channel.get_id(),
DlcProtocolType::Renew {
trade_params: (protocol_id, trade_params).into(),
},
DlcProtocolType::renew(trade_params, protocol_id, realized_pnl),
)?;

db::positions::Position::set_position_to_resizing(
Expand Down Expand Up @@ -758,7 +752,6 @@ impl TradeExecutor {
.expect("to fit"),
order_matching_fee,
trader_realized_pnl_sat: realized_pnl.map(SignedAmount::to_sat),
is_complete: false,
},
)?;

Expand Down Expand Up @@ -896,9 +889,7 @@ impl TradeExecutor {
previous_id,
&contract_id,
&channel.get_id(),
DlcProtocolType::Settle {
trade_params: (protocol_id, trade_params).into(),
},
DlcProtocolType::settle(trade_params, protocol_id),
)?;

db::positions::Position::set_open_position_to_closing(
Expand Down
2 changes: 0 additions & 2 deletions coordinator/src/trade/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub struct NewTrade {
pub average_price: f32,
pub order_matching_fee: Amount,
pub trader_realized_pnl_sat: Option<i64>,
pub is_complete: bool,
}

#[derive(Debug)]
Expand All @@ -31,5 +30,4 @@ pub struct Trade {
pub timestamp: OffsetDateTime,
pub order_matching_fee: Amount,
pub trader_realized_pnl_sat: Option<i64>,
pub is_complete: bool,
}

0 comments on commit 4887e94

Please sign in to comment.