edtechre / pybroker

Algorithmic Trading in Python with Machine Learning
https://www.pybroker.com
Other
2.09k stars 261 forks source link

Exits and stoploss not working #139

Closed markxbaker closed 2 months ago

markxbaker commented 2 months ago

Hi, been testing this out, looks awesome but am struggling with a few things, can't seem to get the exit conditions working or the stop loss unless I calculate the percentage?

When I run the below it only takes one trade!?

Am prob being a bit dense and apologise I'm advance, but there a lots of crosses that occur so unsure why? Please help!

Enable data source caching for YFinance

pybroker.enable_data_source_cache('yfinance')

Set the ticker for backtest (simplified to use one ticker)

tickers = 'AAPL'

Set up YFinance data source

yfinance = YFinance()

Define indicators

def sma_indicator(data, period): return talib.SMA(data.close, timeperiod=period)

def atr(data, period=10): atr = talib.ATR(data.high, data.low, data.close, timeperiod=period) return atr

Define a dictionary for indicators

indicators = { 'sma_short': pybroker.indicator('sma_short', lambda data: sma_indicator(data, 10)), 'sma_long': pybroker.indicator('sma_long', lambda data: sma_indicator(data, 20)), 'ATR_10': pybroker.indicator('ATR_10', lambda data: atr(data, 10)), }

Backtest configuration

config = StrategyConfig( initial_cash=100_000, fee_mode=FeeMode.PER_SHARE, fee_amount=0.02,

sell_delay=1

)

Execution function

def exec_fn(ctx): sma_short = ctx.indicator('sma_short') sma_long = ctx.indicator('sma_long') atr_10d = ctx.indicator('ATR_10')

# Entry condition: short SMA crosses above long SMA
if not ctx.long_pos():
    if sma_short[-1] > sma_long[-1]:
        ctx.buy_shares = ctx.calc_target_shares(0.10)
        # Set stop loss based on ATR
        stop_loss_calc = ctx.close[-1] - (2.5 * atr_10d[-1])
        stop_loss_pct = ((ctx.close[-1] - stop_loss_calc) / ctx.close[-1]) * 100
        ctx.stop_loss_pct = stop_loss_pct

# Exit condition: short SMA crosses below long SMA
elif sma_short[-1] < sma_long[-1]:
    ctx.sell_all_shares()

Set up strategy and run backtest

strategy = Strategy(yfinance, '3/1/2010', '05/9/2024', config) strategy.add_execution(exec_fn, tickers, indicators=list(indicators.values())) strategy.set_slippage_model(RandomSlippageModel(min_pct=0.01, max_pct=0.02))

Run backtest

result = strategy.backtest(warmup=200, calc_bootstrap=True) result.metrics_df

edtechre commented 2 months ago

This is because of the slippage model. Calling sell_all_shares is not forcing all shares to be sold, but instead has the slippage model applied, so the position is never fully exited.

I will make a fix to the slippage model for this. In the meantime, you can remove the usage of the slippage model.

edtechre commented 2 months ago

This has been fixed in v1.2.2.