Engine: add stop loss integration (fixed & trailing) with tests
This commit is contained in:
82
tests/backtest/test_engine_trailing_stop.py
Normal file
82
tests/backtest/test_engine_trailing_stop.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# tests/backtest/test_engine_trailing_stop.py
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
|
||||
from src.backtest.engine import BacktestEngine
|
||||
from src.backtest.strategy import Strategy, Signal
|
||||
from src.backtest.trade import TradeStatus
|
||||
from src.risk.stops.trailing_stop import TrailingStop
|
||||
|
||||
|
||||
class AlwaysBuyStrategy(Strategy):
|
||||
"""
|
||||
Estrategia dummy:
|
||||
- Compra en la primera vela
|
||||
- Nunca vende
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name="AlwaysBuy", params={})
|
||||
|
||||
def init_indicators(self, data):
|
||||
return data
|
||||
|
||||
def generate_signal(self, idx: int):
|
||||
if idx == 0:
|
||||
return Signal.BUY
|
||||
return Signal.HOLD
|
||||
|
||||
|
||||
def test_trailing_stop_moves_and_closes_position():
|
||||
"""
|
||||
El trailing stop:
|
||||
- se mueve cuando el precio sube
|
||||
- cierra la posición cuando el precio cae
|
||||
"""
|
||||
|
||||
timestamps = pd.date_range(
|
||||
start=datetime(2024, 1, 1),
|
||||
periods=7,
|
||||
freq="1h"
|
||||
)
|
||||
|
||||
data = pd.DataFrame(
|
||||
{
|
||||
"open": [100, 102, 105, 108, 110, 107, 103],
|
||||
"high": [101, 103, 106, 109, 111, 108, 104],
|
||||
"low": [99, 101, 104, 107, 109, 106, 102],
|
||||
"close": [100, 102, 105, 108, 110, 107, 103],
|
||||
"volume": [1, 1, 1, 1, 1, 1, 1],
|
||||
},
|
||||
index=timestamps
|
||||
)
|
||||
|
||||
strategy = AlwaysBuyStrategy()
|
||||
|
||||
engine = BacktestEngine(
|
||||
strategy=strategy,
|
||||
initial_capital=10000,
|
||||
commission=0.0,
|
||||
slippage=0.0,
|
||||
position_size=1.0,
|
||||
stop_loss=TrailingStop(0.05), # 5% trailing
|
||||
)
|
||||
|
||||
engine.run(data)
|
||||
|
||||
# Solo debe haber un trade
|
||||
assert len(engine.trades) == 1
|
||||
|
||||
trade = engine.trades[0]
|
||||
|
||||
# El trade debe cerrarse por stop
|
||||
assert trade.status == TradeStatus.CLOSED
|
||||
assert trade.exit_reason == "Stop Loss"
|
||||
|
||||
# El cierre no debe ser al final del backtest
|
||||
assert trade.exit_time <= data.index[-1]
|
||||
Reference in New Issue
Block a user