mirror of
https://github.com/KhizarImran/backtestingfx.git
synced 2026-07-27 20:17:44 +00:00
feat: stoploss and take profit implementation on the broker.rs
This commit is contained in:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user