commit 48586de436f76617cd8cd9b1343250516dbcbecb Author: Khizar Imran Date: Wed Jun 3 23:39:39 2026 +0100 Initial commit: project strcture & initialisation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5ccb00 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +Cargo.lock +### My claude md file +CLAUDE.md diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5a946f9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "backtestingfx" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/broker.rs b/src/broker.rs new file mode 100644 index 0000000..e629623 --- /dev/null +++ b/src/broker.rs @@ -0,0 +1,57 @@ +use crate::types::{Position, Trade}; + +pub struct Broker{ + pub cash: f64, + pub positions: Vec, + pub trade_history: Vec +} + +impl Broker { + pub fn new(initial_cash: f64) -> self { // does not need &mut because it initialises something new + Broker { + cash: initial_cash, + positions: Vec::new(), + trade_history: Vec::new() + } + } + + 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::) + self.positions.push(Position { + entry_price: price, + lot_size, + is_long: true, + entry_timestamp: timestamp + }); + } + + pub fn sell(&mut self, price: f64, lot_size: f64, timestamp: i64) { // needs to modify the broker with new position. (.push works with the Vec::) + self.positions.push(Position { + entry_price: price, + lot_size, + is_long: false, + entry_timestamp: timestamp + }); + } + + pub fn close_all (&mut self, price:f64, timestamp: i64) { // Instead of .push it uses drain to calculate the close all positions + for position in self.positions.drain(..) { + let pnl = if position.is_long { + (price - position.entry_price) * position.lot_size + } else { + (position.entry_price - price) * position.lot_size + }; + self.cash += pnl; + self.trade_history.push(Trade { + entry_price: position.entry_price, + exit_price: position.exit_price, + lot_size: position.lot_size, + is_long: position.is_long, + pnl, + entry_timestamp: position.entry_timestamp, + exit_timestamp: timestamp + }); + } + } + + +} diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/engine.rs b/src/engine.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d5fe90d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +pub mod types; +pub mod strategy; +pub mod broker; +pub mod engine; +pub mod data; diff --git a/src/strategy.rs b/src/strategy.rs new file mode 100644 index 0000000..cff9c34 --- /dev/null +++ b/src/strategy.rs @@ -0,0 +1,7 @@ +use crate::types::Bar; +use crate::broker::Broker; + +pub trait Strategy { + fn next(&mut self, bar: &Bar, broker: &mut Broker); +} + diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..3f1b7fd --- /dev/null +++ b/src/types.rs @@ -0,0 +1,28 @@ +#[derive(Debug, Clone)] +pub struct Bar { // Initialises the interface for the bar + pub timestamp: i64, + pub open: f64, + pub high: f64, + pub low: f64, + pub close: f64, + pub volume: f64, +} + +#[derive(Debug, Clone)] +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 +} + +#[derive(Debug, Clone)] +pub struct Trade { // the actual trade + pub entry_price: f64, + pub exit_price: f64, + pub lot_size: f64, + pub is_long: bool, + pub pnl: f64, + pub entry_timestamp: i64, + pub exit_timestamp:i64 +}