feat: stoploss and take profit implementation on the broker.rs

This commit is contained in:
KhizarImran
2026-06-13 12:01:44 +01:00
parent 516f6029ac
commit 9847a99561
4 changed files with 65 additions and 7 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ struct BuyEveryBar;
impl Strategy for BuyEveryBar {
fn next (&mut self, bar: &Bar, broker: &mut Broker) {
broker.close_all(bar.close, bar.timestamp); //closes any open positions
broker.buy(bar.close, 1.0, bar.timestamp); // can be more complicated with buy, sells, close position, close all etc.
broker.buy(bar.close, 1.0, bar.timestamp, None, None); // can be more complicated with buy, sells, close position, close all etc.
}
}
+59 -5
View File
@@ -1,5 +1,5 @@
use crate::types::{Position, Trade};
use crate::types::{Position, Trade, Bar};
pub struct Broker{
pub cash: f64,
@@ -22,20 +22,21 @@ impl Broker {
}
}
pub fn buy(&mut self, price: f64, lot_size: f64, timestamp: i64) { // needs to modify the broker with new position. (.push works with the Vec::)
pub fn buy(&mut self, price: f64, lot_size: f64, timestamp: i64, stop_loss: Option<f64>, take_profit: Option<f64>) { // needs to modify the broker with new position. (.push works with the Vec::)
let fill_price = price + self.spread; // buy at ask
self.cash -= self.commission * lot_size; // pay commission
self.positions.push(Position {
id: self.positions.len() as u64,
entry_price: fill_price,
lot_size,
is_long: true,
entry_timestamp: timestamp,
stop_loss,
take_profit
});
}
pub fn sell(&mut self, price: f64, lot_size: f64, timestamp: i64) {
pub fn sell(&mut self, price: f64, lot_size: f64, timestamp: i64, stop_loss: Option<f64>, take_profit: Option<f64>) {
let fill_price = price - self.spread; // buy at ask
self.cash -= self.commission * lot_size; // pay commission // needs to modify the broker with new position. (.push works with the Vec::)
self.positions.push(Position {
@@ -43,7 +44,9 @@ impl Broker {
entry_price: fill_price,
lot_size,
is_long: false,
entry_timestamp: timestamp
entry_timestamp: timestamp,
stop_loss,
take_profit
});
}
@@ -116,4 +119,55 @@ impl Broker {
self.cash + unrealized
}
pub fn check_sl_tp(&mut self, bar: &Bar) {
let mut i = 0;
while i < self.positions.len() {
let fill = {
let p = &self.positions[i];
if p.is_long{
let sl_hit = p.stop_loss.map_or(false, |sl| bar.low <= sl);
let tp_hit = p.take_profit.map_or(false, |tp| bar.high >= tp);
if sl_hit {p.stop_loss}
else if tp_hit {p.take_profit}
else {None}
} else {
let sl_hit = p.stop_loss.map_or(false, |sl| bar.high >= sl);
let tp_hit = p.take_profit.map_or(false, |tp| bar.low <= tp);
if sl_hit {p.stop_loss}
else if tp_hit {p.take_profit}
else {None}
}
};
if let Some(fill_price) = fill {
let position = self.positions.remove(i);
let close_price = if position.is_long {
fill_price - self.spread
} else {
fill_price + self.spread
};
let pnl = if position.is_long {
(close_price - position.entry_price) * position.lot_size
} else {
(position.entry_price - close_price) * position.lot_size
};
self.cash += pnl;
self.trade_history.push(Trade {
entry_price: position.entry_price,
exit_price: close_price,
lot_size: position.lot_size,
is_long: position.is_long,
pnl,
entry_timestamp: position.entry_timestamp,
exit_timestamp: bar.timestamp
});
} else {
i+=1;
}
}
}
}
+1
View File
@@ -21,6 +21,7 @@ impl Engine {
pub fn run (&mut self, strategy: &mut dyn Strategy) -> Stats {
strategy.init(&self.data);
for bar in &self.data {
self.broker.check_sl_tp(bar);
strategy.next(bar, &mut self.broker);
self.equity_curve.push(self.broker.equity(bar.close));
}
+4 -1
View File
@@ -14,7 +14,10 @@ pub struct Position { // this is for the trading position
pub entry_price: f64,
pub lot_size: f64,
pub is_long: bool,
pub entry_timestamp: i64
pub entry_timestamp: i64,
pub stop_loss: Option<f64>,
pub take_profit: Option<f64>
}
#[derive(Debug, Clone)]