Metadata-Version: 2.4
Name: twap-engine
Version: 0.2.0
Summary: Exchange-agnostic TWAP (Time-Weighted Average Price) order execution engine with slippage-abort, plus an optional ATR-based stop-loss calculator. Works on any ccxt-supported exchange.
Author: Akin Urkmez
License: MIT
Project-URL: Homepage, https://github.com/urkmezakin41-gif/twap-engine
Project-URL: Repository, https://github.com/urkmezakin41-gif/twap-engine
Project-URL: Issues, https://github.com/urkmezakin41-gif/twap-engine/issues
Keywords: twap,trading,crypto,ccxt,algo-trading,execution
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ccxt
Dynamic: license-file

# TWAP Engine

[![PyPI](https://img.shields.io/pypi/v/twap-engine)](https://pypi.org/project/twap-engine/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

An exchange-agnostic **Time-Weighted Average Price (TWAP)** order distribution
engine, plus an optional ATR-based stop-loss **calculator**. Works on any
[ccxt](https://github.com/ccxt/ccxt)-supported exchange (Binance, Bybit,
Kraken, …). It depends on no particular project or infrastructure.

```bash
pip install twap-engine
```

*[Türkçe README](README.tr.md)*

---

## Why

A large order placed in one go moves its own price: it eats the depth of the
order book and the last fills land measurably worse than the first. TWAP
splits that order into slices and spreads them over time.

The engine's job is to do that split **and** to notice when things are going
wrong mid-execution and stop.

| Feature | Behaviour |
|---|---|
| Slicing | Splits a total amount into N slices over a time window |
| Slippage abort | **Cancels the remaining slices** if price drifts past a limit |
| Min-notional guard | Rejects up front if a slice would fall below the exchange minimum |
| Smart stop *(optional)* | ATR-based stop-loss suggestion that widens with volatility |
| Exchange agnostic | Anything `ccxt` speaks |

## Design decision: it calculates, it never orders

The smart-stop layer **computes** a stop level. It never **places** an order.

That boundary is not documented — it is enforced by two tests. One checks the
behaviour, the other scans the source for order-placing calls and fails if it
finds any.

A calculation layer that can quietly place orders would be making decisions
inside someone else's system on my behalf. I don't know who uses this
library; how much authority I hand it is my responsibility, not theirs.

The same principle covers failure: **if the stop calculator crashes, the TWAP
flow is unaffected.** An optional helper must never take down the main job.
There is a test for that too.

## Tests

```
test_engine.py                          3/3
test_smart_stop.py                     11/11
                                    ─────────
                                       14/14
```

Four of them are boundary tests rather than unit tests:

| Test | Guarantees |
|---|---|
| `test_broken_calculator_never_blocks_twap` | A broken helper cannot stop the main flow |
| `test_smart_stop_never_orders` | The calculator does not place orders — behaviourally |
| `test_no_order_calls_in_smart_stop_source` | No order call exists **in the source at all** |
| `test_no_proprietary_guardian_references` | No reference to my private risk stack leaked into this package |

The last one is why this package can exist. The engine was originally written
inside my own trading system, wired to proprietary risk layers. Publishing it
meant cutting it out — and "I removed it" is not a verifiable claim. A single
import, a comment, or a variable name can carry information out.

So the separation is a test. Documentation goes stale; a test re-proves itself
on every run.

## Usage

```python
import asyncio
import ccxt.async_support as ccxt
from twap_engine import TWAPEngine

async def main():
    exchange = ccxt.binance({
        "apiKey": "...",
        "secret": "...",
        "enableRateLimit": True,
    })
    engine = TWAPEngine(exchange)

    result = await engine.execute(
        symbol="BTC/USDT",
        side="buy",
        total_amount=1000.0,   # quote currency
        slices=5,
        interval_seconds=60,
        max_slippage_pct=0.3,  # abort the rest beyond this drift
    )
    print(result)
    await exchange.close()

asyncio.run(main())
```

Run `python demo_smart_stop.py` to compare a fixed 1.5% stop against the
ATR-based one on live market data.

## Scope

Deliberately narrow: it distributes an order, watches slippage, suggests a
stop. It does **not** forecast the market and does **not** manage a portfolio.
The prediction and risk layers of my own system are intentionally absent —
that is a scope decision, not a missing feature.

## License

MIT — commercial use included. See [LICENSE](LICENSE).
