stock/README.md
2025-08-15 12:19:07 +02:00

227 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Multi-Asset Portfolio Simulator (Yahoo Finance, Python)
Szybki symulator wielo-aktywny z jedną wspólną kasą.
Działa w pętli co 2 minuty i dla paczki tickerów:
- pobiera **batch** danych z Yahoo jednym zapytaniem (`yfinance.download`),
- **dopina tylko nowe świece** (cache ostatniego czasu per ticker),
- liczy sygnał na **close** każdej świecy,
- **egzekwuje** zlecenie na **kolejnym open** (bardziej realistycznie),
- prowadzi portfel (wspólne saldo, SL/TP intrabar, prowizja, poślizg),
- zapisuje wyniki do `dane/` oraz liczy metryki **MaxDD, Sharpe, CAGR**.
> Uwaga: to **symulacja** oparta o dane z Yahoo. Nie składa prawdziwych zleceń.
---
## Funkcje (skrót)
- Multi-asset (~20 domyślnych: krypto + forex + złoto `GC=F`)
- Batch download (znacznie szybciej niż pojedynczo)
- Tylko nowe świece (bez pobierania pełnej historii co rundę)
- Sygnał: EMA200 + SMA(20/50) + RSI(14) + ATR-SL/TP + filtry:
**MACD, Stochastic, Bollinger, ADX, Supertrend**
- Egzekucja na **kolejnym OPEN**
- Portfel: **jedna** kasa dla wszystkich instrumentów, risk per trade (% equity)
- Zapisy CSV + **portfolio_summary** z MaxDD / Sharpe (annual) / CAGR
---
## Wymagania
- Python 3.9+
- `pip install yfinance pandas numpy`
---
## Szybki start
```bash
# 1) instalacja
chmod +x install.sh
./install.sh
# 2) uruchomienie (wirtualne środowisko)
source venv/bin/activate
python app.py
# (opcjonalnie w tle)
nohup python app.py > output.log 2>&1 &
```
Logi lecą do `stdout` (lub do `output.log` przy `nohup`).
---
## Struktura plików
```
project/
├─ app.py # główna pętla: batch → nowe świece → decyzje → egzekucja → zapis
├─ config.py # konfiguracja (tickery, interwał, risk, katalog 'dane', itp.)
├─ data.py # fetch_batch(): pobieranie paczki tickerów z yfinance
├─ indicators.py # implementacje wskaźników (SMA/EMA/RSI/ATR/MACD/…)
├─ strategy.py # evaluate_signal(): logika generowania sygnałów + SL/TP + rpu
├─ portfolio.py # model portfela: pozycje, pending orders, SL/TP, PnL, equity
├─ metrics.py # metryki portfelowe: MaxDD, Sharpe (annualized), CAGR
├─ io_utils.py # zapisy do 'dane/': trades, equity, summary; tworzenie katalogów
├─ requirements.txt # zależności (yfinance, pandas, numpy)
└─ install.sh # instalator: venv + pip install -r requirements.txt
```
### Co jest w każdym pliku?
- **`config.py`**
Definiuje `CFG` (tickers, interwał, okres pobierania `yf_period`, minimalna historia, risk, kasa startowa, SL/TP, katalog wyjściowy).
Zmienisz tu listę instrumentów lub parametry ryzyka.
- **`data.py`**
`fetch_batch(tickers, period, interval)` — jedno zapytanie do Yahoo dla wielu tickerów. Zwraca słownik `{ticker: DataFrame}` z kolumnami `open, high, low, close, volume`.
- **`indicators.py`**
Wskaźniki: `sma, ema, rsi, atr, macd, stoch_kd, bollinger, adx_val, supertrend`.
- **`strategy.py`**
`evaluate_signal(df)``Decision(signal, sl, tp, rpu)`
- **signal**: `BUY` / `SELL` / `NONE`
- **sl/tp**: poziomy na bazie ATR i RR
- **rpu** (*risk per unit*): ile ryzyka na jednostkę (do wyliczenia wielkości pozycji)
- **`portfolio.py`**
Model portfela z jedną kasą:
- egzekucja **na kolejnym OPEN** (pending orders),
- SL/TP intrabar,
- prowizja i poślizg,
- `portfolio_equity` (czas, equity) i lista `trades`.
- **`metrics.py`**
Metryki portfela na bazie krzywej equity:
- **Max Drawdown** minimalna wartość `equity/rolling_max - 1`,
- **Sharpe annualized** z 1-min zwrotów (525 600 okresów/rok),
- **CAGR** roczna złożona stopa wzrostu.
- **`io_utils.py`**
Tworzy strukturę `dane/`, zapisuje:
- `dane/portfolio_equity.csv` equity w czasie,
- `dane/portfolio_summary.txt` JSON z metrykami i statystyką,
- `dane/<TICKER>/<TICKER>_trades.csv` dziennik zagrań per instrument.
- **`app.py`**
Główna pętla:
1) `fetch_batch` → nowe świeczki,
2) dla każdego **nowego** bara: najpierw egzekucja pending na **open**, potem sygnał na **close** i zaplanowanie zlecenia na **kolejny open**,
3) zapis CSV + metryki,
4) pauza do pełnych 2 minut na rundę.
---
## Struktura wyjściowa (w `dane/`)
```
dane/
├─ portfolio_equity.csv # [time(ms), equity, datetime]
├─ portfolio_summary.txt # JSON z metrykami (MaxDD, Sharpe, CAGR, itp.)
├─ BTC-USD/
│ └─ BTC-USD_trades.csv # dziennik transakcji dla BTC
├─ ETH-USD/
│ └─ ETH-USD_trades.csv
└─ ...
```
**`*_trades.csv`** (kolumny):
`time, datetime, ticker, action(OPEN/CLOSE), side(long/short), price, size, pnl, reason, equity_after`
---
## Konfiguracja (najczęściej zmieniane)
Otwórz `config.py`:
```python
CFG.tickers = ["BTC-USD","ETH-USD","EURUSD=X", ...] # Twoja lista
CFG.interval = "1m" # 1m / 2m / 5m / 15m / 30m / 60m / 1h
CFG.yf_period = "2d" # krótszy = szybciej; dopasuj do interwału
CFG.risk_per_trade = 0.005 # 0.5% equity na trade
CFG.starting_cash = 10000.0 # kasa startowa (w jednostce bazowej)
CFG.sl_atr_mult = 2.0 # ile ATR do SL
CFG.tp_rr = 1.5 # stosunek TP do ryzyka
CFG.root_dir = "dane" # katalog wyjściowy
```
> **Tip**: przy zmianie interwału ustaw odpowiednie `yf_period` (np. 1m→2d, 5m→10d, 1h→60d), żeby mieć min. ~250 barów do wskaźników.
---
## Jak to działa (timeline 1 świecy)
1. Nowy bar `t` przychodzi z Yahoo.
2. Jeśli był **pending order** zaplanowany na **bar `t`**, **otwiera się** na jego **OPEN**.
3. Jeśli jest otwarta pozycja, sprawdzamy **SL/TP intrabar** (`low/high`).
4. Na **CLOSE** bara `t` liczymy sygnał i **plan** (pending) na **OPEN** bara `t+1`.
5. Snapshot portfelowego equity po close.
---
## Metryki
- **MaxDD**: min wartość z `(equity/rolling_max - 1)`.
- **Sharpe (annualized)**: liczone z 1-min zwrotów `pct_change`, skalowane przez √(525 600).
(Brak stopy wolnej od ryzyka/rf ~ 0 w tej wersji.)
- **CAGR**: `((equity_end/equity_start)^(1/lata)) - 1`.
> Uwaga: przy bardzo krótkich danych te metryki mogą być niestabilne.
---
## FAQ
**Q: Chcę inne interwały (np. 5m).**
A: Zmień `CFG.interval = "5m"` oraz `CFG.yf_period = "10d"` (żeby mieć ≥250 barów).
**Q: Jak dodać/zmienić tickery?**
A: Zedytuj listę w `config.py`. Dla złota używamy `GC=F` (futures).
**Q: Foldery per ticker nie powstają od razu.**
A: Tworzą się na starcie (`ensure_dirs`). Jeśli jakiś ticker nie ma danych z Yahoo, plik z transakcjami może nie powstać — ale katalog jest.
**Q: Wolno działa?**
A: Ta wersja używa **jednego** zapytania na rundę + tylko **nowe** świece. Dalsze przyspieszenie: rozbij tickery na dwie paczki, jeśli Yahoo dławi się liczbą symboli.
**Q: Jak uruchomić jako usługę systemd?**
A:
```ini
# /etc/systemd/system/portfolio.service
[Unit]
Description=Multi-Asset Portfolio Simulator
After=network.target
[Service]
User=USER
WorkingDirectory=/ścieżka/do/project
ExecStart=/ścieżka/do/project/venv/bin/python /ścieżka/do/project/app.py
Restart=always
[Install]
WantedBy=multi-user.target
```
Potem:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now portfolio.service
journalctl -u portfolio.service -f
```
---
## Troubleshooting
- **Yahoo 404 / brak danych dla symbolu** → Yahoo czasem zwraca puste dane. Po prostu pomija dany ticker w tej rundzie.
- **Za mało świec (history_min_bars)** → zwiększ `yf_period`.
- **Błędy czasu** → wymuszamy UTC; jeśli masz własne źródło, ujednolicaj strefę.
- **Sharpe = 0** → zbyt krótki okres lub zerowa zmienność w danych (rzadkie).
---
## Licencja
Ten kod jest przykładowy/edukacyjny; używaj na własną odpowiedzialność. Nie stanowi porady inwestycyjnej.