mirror of
https://github.com/KhizarImran/backtestingfx.git
synced 2026-08-18 06:28:04 +00:00
getting it ready for publishing
This commit is contained in:
+2
-2
@@ -4,9 +4,9 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "backtestingfx"
|
name = "_backtestingfx"
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
pyo3 = { version = "0.28", features = ["extension-module"]}
|
pyo3 = { version = "0.28", features = ["extension-module"]}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
from backtestingfx._backtestingfx import Bar, Engine, Stats, Broker # type: ignore
|
||||||
|
from backtestingfx.backtest import Strategy, Backtest
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,100 @@
|
|||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from backtestingfx import _backtestingfx as _rust # type: ignore
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
|
class Strategy:
|
||||||
|
def __init__(self):
|
||||||
|
self._bars: Any = None
|
||||||
|
self._bar: Any = None
|
||||||
|
self._broker: Any = None
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def buy(self, lot_size, stop_loss=None, take_profit=None):
|
||||||
|
self._broker.buy(
|
||||||
|
self._bar.close, lot_size, self._bar.timestamp, stop_loss, take_profit
|
||||||
|
)
|
||||||
|
|
||||||
|
def sell(self, lot_size, stop_loss=None, take_profit=None):
|
||||||
|
self._broker.sell(
|
||||||
|
self._bar.close, lot_size, self._bar.timestamp, stop_loss, take_profit
|
||||||
|
)
|
||||||
|
|
||||||
|
def close_all(self):
|
||||||
|
self._broker.close_all(self._bar.close, self._bar.timestamp)
|
||||||
|
|
||||||
|
def close_position(self, id):
|
||||||
|
self._broker.close_position(id, self._bar.close, self._bar.timestamp)
|
||||||
|
|
||||||
|
|
||||||
|
class _Adapter:
|
||||||
|
def __init__(self, strategy):
|
||||||
|
self._strategy = strategy
|
||||||
|
|
||||||
|
def init(self, bars):
|
||||||
|
self._strategy._bars = bars
|
||||||
|
self._strategy.init()
|
||||||
|
|
||||||
|
def next(self, bar, broker):
|
||||||
|
self._strategy._bar = bar
|
||||||
|
self._strategy._broker = broker
|
||||||
|
self._strategy.next()
|
||||||
|
|
||||||
|
|
||||||
|
class Backtest:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
df,
|
||||||
|
strategy_class,
|
||||||
|
cash=10000.0,
|
||||||
|
commission=0.0,
|
||||||
|
spread=0.0,
|
||||||
|
contract_size=100000.0,
|
||||||
|
quote_to_account=1.0,
|
||||||
|
):
|
||||||
|
self._df = df
|
||||||
|
self._strategy_class = strategy_class
|
||||||
|
self._cash = cash
|
||||||
|
self._commission = commission
|
||||||
|
self._spread = spread
|
||||||
|
self._contract_size = contract_size
|
||||||
|
self._quote_to_account = quote_to_account
|
||||||
|
|
||||||
|
def _to_bars(self):
|
||||||
|
bars = []
|
||||||
|
for idx, row in self._df.iterrows():
|
||||||
|
if isinstance(idx, pd.Timestamp):
|
||||||
|
ts = int(idx.timestamp())
|
||||||
|
else:
|
||||||
|
ts = int(pd.Timestamp(row["timestamp"]).timestamp()) # type: ignore
|
||||||
|
|
||||||
|
bars.append(
|
||||||
|
_rust.Bar( # type: ignore
|
||||||
|
timestamp=ts,
|
||||||
|
open=float(row["open"]),
|
||||||
|
high=float(row["high"]),
|
||||||
|
low=float(row["low"]),
|
||||||
|
close=float(row["close"]),
|
||||||
|
volume=float(row.get("volume", 0.0)),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return bars
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
bars = self._to_bars()
|
||||||
|
engine = _rust.Engine( # type: ignore
|
||||||
|
bars,
|
||||||
|
self._cash,
|
||||||
|
self._commission,
|
||||||
|
self._spread,
|
||||||
|
self._contract_size,
|
||||||
|
self._quote_to_account,
|
||||||
|
)
|
||||||
|
strategy = self._strategy_class()
|
||||||
|
return engine.run(_Adapter(strategy))
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["maturin>=1.0,<2.0"]
|
||||||
|
build-backend = "maturin"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "backtestingfx"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "FX backtesting library built in Rust"
|
||||||
|
requires-python = ">=3.9"
|
||||||
|
dependencies = ["pandas"]
|
||||||
|
|
||||||
|
[tool.maturin]
|
||||||
|
module-name = "backtestingfx._backtestingfx"
|
||||||
|
features = ["pyo3/extension-module"]
|
||||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from backtest import Backtest, Strategy
|
from backtestingfx import Backtest, Strategy
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from lse import LSE
|
from lse import LSE
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ df.to_csv("data/EURUSD_1H.csv", index=False)
|
|||||||
class BuyEveryBar(Strategy):
|
class BuyEveryBar(Strategy):
|
||||||
def next(self):
|
def next(self):
|
||||||
self.close_all()
|
self.close_all()
|
||||||
self.buy(1.0)
|
self.buy(0.1)
|
||||||
|
|
||||||
|
|
||||||
df = pd.read_csv("data/EURUSD_1H.csv")
|
df = pd.read_csv("data/EURUSD_1H.csv")
|
||||||
@@ -25,11 +25,4 @@ df = pd.read_csv("data/EURUSD_1H.csv")
|
|||||||
bt = Backtest(df, BuyEveryBar, cash=10000.0, commission=0.0, spread=0.0001)
|
bt = Backtest(df, BuyEveryBar, cash=10000.0, commission=0.0, spread=0.0001)
|
||||||
stats = bt.run()
|
stats = bt.run()
|
||||||
|
|
||||||
print(f"Return: {stats.total_return_pct:.2f}%")
|
print(stats)
|
||||||
print(f"Trades: {stats.num_trades}")
|
|
||||||
print(f"Win Rate: {stats.win_rate_pct:.1f}%")
|
|
||||||
print(f"Avg PnL: {stats.avg_pnl:.5f}")
|
|
||||||
print(f"Best Trade: {stats.best_trade:.5f}")
|
|
||||||
print(f"Worst Trade: {stats.worst_trade:.5f}")
|
|
||||||
print(f"Max Drawdown: {stats.max_drawdown_pct:.2f}%")
|
|
||||||
print(f"Profit Factor:{stats.profit_factor:.2f}")
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ pub mod types;
|
|||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
|
#[pyo3(name = "_backtestingfx")]
|
||||||
fn backtestingfx(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn backtestingfx(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_class::<types::Bar>()?;
|
m.add_class::<types::Bar>()?;
|
||||||
m.add_class::<stats::Stats>()?;
|
m.add_class::<stats::Stats>()?;
|
||||||
|
|||||||
Reference in New Issue
Block a user