Algorithmic trading competition library — leveraged long/short backtest engine
Project description
cnlib — Code Night Algorithmic Trading Library
Leveraged long/short backtest engine for the Code Night trading competition.
Participants write a strategy, the platform runs it, results are ranked.
How It Works
Three synthetic crypto assets — kapcoin-usd_train, metucoin-usd_train, tamcoin-usd_train — modeled after BTC, SOL, and XRP volatility profiles.
- Starting capital: $3,000
- Available leverage: 1x, 2x, 3x, 5x, 10x
- Positions: Long (profit when price rises) or Short (profit when price falls)
predict()is called on every candle close — you decide what to do next
Installation
pip install cnlib
Or from source:
git clone https://github.com/IYTE-Yazilim-Toplulugu/code-night-lib.git
cd code-night-lib
pip install -e .
Quickstart
Create a strategy.py file anywhere:
from cnlib.base_strategy import BaseStrategy
class MyStrategy(BaseStrategy):
def predict(self, data):
closes = data["kapcoin-usd_train"]["Close"]
if closes.iloc[-1] > closes.iloc[-2]:
signal = 1 # price went up → go long
else:
signal = -1 # price went down → go short
return [
{"coin": "kapcoin-usd_train", "signal": signal, "allocation": 0.5, "leverage": 2},
{"coin": "metucoin-usd_train", "signal": 0, "allocation": 0.0, "leverage": 1},
{"coin": "tamcoin-usd_train", "signal": 0, "allocation": 0.0, "leverage": 1},
]
Run the backtest:
from cnlib import backtest
from strategy import MyStrategy
result = backtest.run(MyStrategy(), initial_capital=3000.0)
result.print_summary()
Output:
=======================================================
BACKTEST RESULTS
=======================================================
Initial Capital : $ 3,000.00
Final Portfolio : $ 3,220.35
Net P&L : $ +220.35
Return : +7.3450%
-------------------------------------------------------
Total Candles : 1,000
Total Trades : 54
Liquidations : 0
Liquidation Loss : $ 0.00
Validation Errors : 0
=======================================================
The predict() Contract
Called on every candle close. Receives all historical OHLCV data up to the current candle.
Input
data = {
"kapcoin-usd_train": pd.DataFrame, # columns: Date, Open, High, Low, Close, Volume
"metucoin-usd_train": pd.DataFrame,
"tamcoin-usd_train": pd.DataFrame,
}
Each DataFrame only contains candles up to now — no future data leakage.
Output
A list with exactly one entry per coin, every candle:
return [
{"coin": "kapcoin-usd_train", "signal": 1, "allocation": 0.5, "leverage": 10},
{"coin": "metucoin-usd_train", "signal": -1, "allocation": 0.3, "leverage": 2},
{"coin": "tamcoin-usd_train", "signal": 0, "allocation": 0.0, "leverage": 1},
]
| Field | Type | Description |
|---|---|---|
coin |
str |
One of kapcoin-usd_train, metucoin-usd_train, tamcoin-usd_train |
signal |
int |
1 = long, -1 = short, 0 = close any open position |
allocation |
float |
Fraction of portfolio to allocate [0.0 – 1.0] |
leverage |
int |
1, 2, 3, 5, or 10 |
Rules
- All three coins must appear in every list — no omissions
- To hold an open position, re-state the same
signal - To stay flat, use
signal=0, allocation=0.0 signal=0→allocationmust be0.0- Sum of active allocations cannot exceed
1.0 - Leverage must be one of
{1, 2, 3, 5, 10}(ignored whensignal=0) - Violations raise
ValidationError— that candle is skipped, positions are held
Liquidation
Positions are force-closed when the candle's intrabar extreme hits the liquidation threshold — longs on the candle Low, shorts on the candle High. Capital is fully lost on liquidation — no cash is returned.
Long → liquidated when Low ≤ entry × (1 - 1/leverage)
Short → liquidated when High ≥ entry × (1 + 1/leverage)
Example: long at $100 with 10x leverage
Liquidation price = 100 × (1 - 1/10) = $90
If the candle Low touches $90 or below → position wiped out
Position Sizing
allocation is a fraction of your current total portfolio value, not just cash:
# Portfolio value: $3,000, allocation=0.4, leverage=5
allocated_capital = 3000 × 0.4 = $1,200
effective_exposure = $1,200 × 5 = $6,000
# If price rises 2%:
pnl = $1,200 × 5 × 0.02 = +$120 (+10% on allocated capital)
Strategy State
self persists between candles — use it to store state:
class MyStrategy(BaseStrategy):
def __init__(self):
super().__init__()
self.prev_signal = {
"kapcoin-usd_train": 0,
"metucoin-usd_train": 0,
"tamcoin-usd_train": 0,
}
self.entry_prices = {}
def predict(self, data):
# self.candle_index → current candle number (0-based)
# self.coin_data → full OHLCV history dict
...
Result Object
result = backtest.run(strategy)
result.print_summary() # formatted console output
result.portfolio_dataframe() # time-series DataFrame: candle_index, portfolio_value, cash, *_price
result.trade_history # list of dicts for candles where trades occurred
result.final_portfolio_value # float
result.net_pnl # float
result.return_pct # float
result.total_liquidations # int
result.validation_errors # int
Project Structure
code-night-lib/
├── pyproject.toml
├── cnlib/
│ ├── base_strategy.py # BaseStrategy — inherit this
│ ├── backtest.py # backtest.run()
│ ├── portfolio.py # position & liquidation logic
│ ├── validator.py # predict() output validation
│ └── data/
│ ├── kapcoin-usd_train.parquet
│ ├── metucoin-usd_train.parquet
│ └── tamcoin-usd_train.parquet
└── docs/
└── README.md # participant guide (Turkish)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cnlib-0.1.4.tar.gz.
File metadata
- Download URL: cnlib-0.1.4.tar.gz
- Upload date:
- Size: 206.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
424a91f0b2150d822fe4271eee22dede1e4f28e4208a6d56363ab4f30af70cd4
|
|
| MD5 |
75bb94a8984dd3e1c274ca320a10f5b9
|
|
| BLAKE2b-256 |
f8a21d89d17a7faa709582da54254da7220e9d4ee570a922cf48c89de6f26f54
|
File details
Details for the file cnlib-0.1.4-py3-none-any.whl.
File metadata
- Download URL: cnlib-0.1.4-py3-none-any.whl
- Upload date:
- Size: 207.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ebb6c167b9036d662d0a27af77ee1099769e30cd8b6cd73ed90d9eec87f946f
|
|
| MD5 |
8d5e2bef44e27e7f78e43646ef65e1f3
|
|
| BLAKE2b-256 |
99425989dfe37384f7ab6e593c745d101453d86a449ca89f02a60fea29b4baef
|