# 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//_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.