use std::sync::Arc;
use crate::{account::BrokerageAccount, db_util, security::Security};
use anyhow::Result;
use bson::oid::ObjectId;
use mongodb::{ClientSession, Database};
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum TradeSide {
Buy,
Sell,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct TradeExecution {
_id: bson::oid::ObjectId,
brokerage_account_id: bson::oid::ObjectId,
brokerage_execution_id: String,
commission: f64,
execution_timestamp_ms: i64,
quantity: f64,
price: f64,
security_id: bson::oid::ObjectId,
side: TradeSide,
}
impl TradeExecution {
pub const COLLECTION_NAME: &'static str = "trade_executions";
pub fn builder() -> Builder {
Builder::new()
}
pub fn id(&self) -> ObjectId {
self._id
}
pub fn brokerage_account_id(&self) -> ObjectId {
self.brokerage_account_id
}
pub fn brokerage_execution_id(&self) -> &str {
&self.brokerage_execution_id
}
pub fn execution_timestamp_ms(&self) -> i64 {
self.execution_timestamp_ms
}
pub fn commission(&self) -> f64 {
self.commission
}
pub fn quantity(&self) -> f64 {
self.quantity
}
pub fn price(&self) -> f64 {
self.price
}
pub fn security_id(&self) -> ObjectId {
self.security_id
}
pub fn side(&self) -> &TradeSide {
&self.side
}
pub async fn insert(
&self,
db: &Database,
session: Option<Arc<Mutex<ClientSession>>>,
) -> Result<()> {
db_util::insert(self, db, Self::COLLECTION_NAME, session).await
}
pub async fn find_by_id(db: &Database, id: ObjectId) -> Result<Option<Self>> {
let result = db
.collection::<Self>(Self::COLLECTION_NAME)
.find_one(bson::doc! {"_id": id})
.await?;
Ok(result)
}
pub async fn find_by_brokerage_execution_id(
db: &Database,
execution_id: &str,
) -> Result<Option<Self>> {
let result = db
.collection::<Self>(Self::COLLECTION_NAME)
.find_one(bson::doc! {"brokerage_execution_id": execution_id})
.await?;
Ok(result)
}
pub async fn brokerage_account(&self, db: &Database) -> Result<BrokerageAccount> {
Ok(BrokerageAccount::find_by_id(db, self.brokerage_account_id)
.await?
.unwrap())
}
pub async fn security(&self, db: &Database) -> Result<Security> {
Ok(Security::find_by_id(db, self.security_id).await?.unwrap())
}
}
pub struct Builder {
_id: bson::oid::ObjectId,
brokerage_account_id: Option<bson::oid::ObjectId>,
brokerage_execution_id: Option<String>,
execution_timestamp_ms: Option<i64>,
commission: Option<f64>,
quantity: Option<f64>,
price: Option<f64>,
security_id: Option<bson::oid::ObjectId>,
side: Option<TradeSide>,
}
impl Builder {
fn new() -> Self {
Self {
_id: ObjectId::new(),
brokerage_account_id: None,
brokerage_execution_id: None,
execution_timestamp_ms: None,
commission: None,
quantity: None,
price: None,
security_id: None,
side: None,
}
}
pub fn from_trade_execution(trade_execution: &TradeExecution) -> Self {
Self {
_id: ObjectId::new(),
brokerage_account_id: Some(trade_execution.brokerage_account_id),
brokerage_execution_id: Some(trade_execution.brokerage_execution_id.clone()),
execution_timestamp_ms: Some(trade_execution.execution_timestamp_ms),
commission: Some(trade_execution.commission),
quantity: Some(trade_execution.quantity),
price: Some(trade_execution.price),
security_id: Some(trade_execution.security_id),
side: Some(trade_execution.side.clone()),
}
}
pub fn brokerage_account_id(mut self, id: bson::oid::ObjectId) -> Self {
self.brokerage_account_id = Some(id);
self
}
pub fn brokerage_execution_id(mut self, id: &str) -> Self {
self.brokerage_execution_id = Some(id.to_owned());
self
}
pub fn execution_timestamp_ms(mut self, timestamp: i64) -> Self {
self.execution_timestamp_ms = Some(timestamp);
self
}
pub fn commission(mut self, commission: f64) -> Self {
self.commission = Some(commission);
self
}
pub fn quantity(mut self, quantity: f64) -> Self {
self.quantity = Some(quantity);
self
}
pub fn price(mut self, price: f64) -> Self {
self.price = Some(price);
self
}
pub fn security_id(mut self, id: bson::oid::ObjectId) -> Self {
self.security_id = Some(id);
self
}
pub fn side(mut self, side: TradeSide) -> Self {
self.side = Some(side);
self
}
pub fn build(self) -> Result<TradeExecution> {
Ok(TradeExecution {
_id: self._id,
brokerage_account_id: self.brokerage_account_id.unwrap(),
brokerage_execution_id: self.brokerage_execution_id.unwrap(),
execution_timestamp_ms: self.execution_timestamp_ms.unwrap(),
commission: self.commission.unwrap(),
quantity: self.quantity.unwrap(),
price: self.price.unwrap(),
security_id: self.security_id.unwrap(),
side: self.side.unwrap(),
})
}
}