Metadata-Version: 2.4
Name: overfitting
Version: 0.4.0
Summary: A Robust Futures CryptoCurrency Backtesting Library.
Author-email: Dohyun Kim <dohyun.k.july@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/dohyunkjuly/overfitting
Project-URL: Source, https://github.com/dohyunkjuly/overfitting
Project-URL: Author, https://github.com/dohyunkjuly
Keywords: algo,bitcoin,ethereum,crypto,cryptocurrency,crypto derivatives,futures,finance,quantitative,liquidation,solana,systematic,quant,trading
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Framework :: Jupyter
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.17.0
Requires-Dist: pandas>=0.25.0
Requires-Dist: seaborn
Requires-Dist: matplotlib
Requires-Dist: scipy
Requires-Dist: plotly
Requires-Dist: PySide6
Provides-Extra: examples
Requires-Dist: notebook; extra == "examples"
Requires-Dist: ipykernel; extra == "examples"
Requires-Dist: ipython; extra == "examples"
Provides-Extra: dev
Requires-Dist: twine>=4.0.2; extra == "dev"
Dynamic: license-file

# Overfitting (Futures Backtesting)

Overfitting simulates a realistic crypto futures trading environment including 
- **Liquidation**, **Margin**, **Leverage** for stress testing
- **Multiple Currency** Trading (e.g., backtesting BTC PERP & ETH PERP at the same time)
- Four Different Order Types: LIMIT, MARKET, STOP_LIMIT, STOP_MARKET
- Slippage/Commission Setting

![Backtest Viewer](https://raw.githubusercontent.com/dohyunkjuly/overfitting/main/documents/viewer.gif)

## Installation
    $ pip install overfitting

## Usage
```python
import pandas as pd
from overfitting import Strategy, BacktestViewer
from overfitting.indicators import SMA

def load_data():
    df = pd.read_csv('./data/BTCUSDT.csv')
    benchamrk_df = pd.read_csv('./data/BTCUSDT.csv') # BTC buy and Hold
    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
    df.set_index('timestamp', inplace=True)

    start_time = pd.to_datetime('2023-01-01 00:00:00')
    df = df.loc[start_time:]

    return df, benchamrk_df
    
class MyStrategy(Strategy):
    def init(self):
        self.asset = 'BTC'
        self.set_leverage(self.asset, 1)

        self.sma_short = SMA(self, self.asset, source="close", window=20)
        self.sma_long = SMA(self, self.asset, source="close", window=50)

    def next(self, i):
        if i == 0:
            return

        sma_short = self.sma_short[i]
        sma_long = self.sma_long[i]
        previous_sma_short = self.sma_short[i - 1]
        previous_sma_long = self.sma_long[i - 1]

        if (
            pd.isna(sma_short) or pd.isna(sma_long) or
            pd.isna(previous_sma_short) or pd.isna(previous_sma_long)
        ):
            return

        position = self.get_position(self.asset)

        # Golden cross (entry)
        if previous_sma_short <= previous_sma_long and sma_short > sma_long and position.qty == 0:
            open_price = self.open(self.asset, i)
            lot_size = self.get_balance() // open_price
            self.limit_order(self.asset, lot_size, open_price)

        # Death cross (exit)
        if previous_sma_short >= previous_sma_long and sma_short < sma_long and position.qty > 0:
            self.market_order(self.asset, -position.qty)

backtest_data, benchmark_data = load_data()
strategy = MyStrategy(
    data=backtest_data,
    benchmark=benchmark_data, # Default = None Optional
    initial_capital=100_000, # Default Optional
    commission_rate=0.0002, # Default Optional
    maint_margin_rate=0.005, # Default Optional
    maint_amount=50  # Default Optional
)
returns = strategy.run()
strategy.plot(returns)

# Show Backtest Viewer UI
# BacktestViewer(strategy).show()
```

Results
-------
```text
Performance Summary
Number of Years               1.66000000
Start Date           2023-01-01 00:00:00
End Date             2024-08-29 00:00:00
Initial Balance         100,000.00000000
Final Balance           205,328.91120000
CAGR                          0.52684228
Cumulative Return             2.05328911
Sharpe Ratio                  1.24678659
Sortino Ratio                 3.54979579
Max Drawdown                 -0.26332695
Daily Value At Risk          -0.04147282
Skew                          0.44515551
Kurtosis                      2.66444346
Total Trades                182.00000000
Winning Trades               69.00000000
Losing Trades               113.00000000
Win Rate (%)                 37.91208791
Gross Profit            399,044.19246000
Gross Loss             -293,715.28126000
Net Profit              105,328.91120000
Avg Return (%)                0.38834383
Avg Profit (%)                3.54140613
Avg Loss (%)                 -1.53697740
  Net drawdown in %  Peak date Valley date Recovery date Duration
0         26.332695 2024-03-13  2024-06-30           NaT      NaN
1         19.678014 2023-03-20  2023-09-07    2023-10-26      159
2          6.297244 2023-12-07  2024-01-24    2024-02-14       50
3          5.585429 2023-01-22  2023-02-14    2023-02-17       20
4          3.898568 2023-02-17  2023-03-11    2023-03-15       19
5          3.336877 2023-11-12  2023-11-18    2023-12-07       19
6          2.699556 2024-02-20  2024-02-26    2024-03-01        9
7          0.767196 2024-03-01  2024-03-03    2024-03-06        4
8          0.324161 2023-01-03  2023-01-07    2023-01-18       12
9          0.019817 2023-11-03  2023-11-04    2023-11-07        3
```

## Performance Visualizations Examples

![Cumulative Returns](https://raw.githubusercontent.com/dohyunkjuly/overfitting/main/documents/culmulative_returns.png)
![Daily Drawdowns](https://raw.githubusercontent.com/dohyunkjuly/overfitting/main/documents/daily_drawdowns.png)
![Monthly Heat Maps](https://raw.githubusercontent.com/dohyunkjuly/overfitting/main/documents/monthly_heat_maps.png)
![Rolling Sharpe Ratio](https://raw.githubusercontent.com/dohyunkjuly/overfitting/main/documents/rolling_sharpe_ratio.png)

## Liquidation Handling

The liquidation logic is based on **isolated margin mode**:

- **Initial Margin** = Entry Price × Quantity / Leverage  
- **Maintenance Margin** = Entry Price × Quantity × Maintenance Margin Rate − Maintenance Amount  
- **Liquidation Price** is then calculated based on whether the position is long or short.
    - Long Position Liquidation Price => Entry Price - (Initial Margin - Maintenance Margin)
    - Short Position Liquidation Price => Entry Price + (Initial Margin - Maintenance Margin)

When the price crosses the calculated liquidation level, the position is force-closed and the **entire margin is lost**.

## Supported Order Types
Supports four order types: LIMIT, MARKET, STOP LIMIT, and STOP MARKET. Each behaves according to standard trading conventions.

[NOTE] Rules
- For MAKRET Orders, the system will automatically execute the trade with "open" price.
- For STOP Orders, the system will automatically trigger the order when:
    - Long: Price (High) >= Stop Price
    - Short: Price (Low) <= Stop Price
- **Stop Order Immediate Rejection Rule**: If a STOP LIMIT or STOP MARKET order would trigger immediately upon creation (because the current price already breaches the stop price), the system rejects the order with "STOP order would Immediately Trigger" message.
 
```python
limit_order(symbol: str, qty: float, price: float)
market_order(symbol: str, qty: float)
stop_limit_order(symbol: str, qty: float, price: float, stop_price: float)
stop_market_order(symbol: str, qty: float, stop_price: float)
```

## Multiple Currency Backtesting
You can simply test multiple currencies by passing data as dict[str, pd.DataFrame]. For examples, please refer to "multi_currency_sma_corss.ipynb" under "examples" folder.

## Upcoming Features

- **Parameter Optimizer**  
  A simple optimizer to help find the best-performing strategy parameters (like SMA windows, thresholds, etc.) based on backtest results.

> 💡 Got feedback or suggestions? Feel free to open an issue or contribute via pull request.
