Commit Graph
12 Commits
Author SHA1 Message Date
matitos c121a4190a Force-recreate containers on deploy and verify the served build
The frontend container was serving the very first build (498-byte index.html)
through every later deploy: `docker compose up -d` did not replace a
config-identical service. Deploy now uses `build --pull` and
`up --force-recreate`, the frontend image writes a .build-version marker, and
the workflow fails the deploy if the served marker != the commit SHA.
2026-09-21 12:12:28 +00:00
matitos 7b97f010c9 Self-heal a stale cached bundle via a build version
Phones kept running old JS because their cached index.html pointed at an old
hashed asset. Both images now bake the commit SHA as BUILD_VERSION; the backend
exposes it at GET /api/version and the client reloads once with a cache-busting
query when its own baked version differs. Guarded by sessionStorage so it cannot
loop. /api/version is unauthenticated like /api/health.
2026-09-21 00:16:43 +00:00
matitos ed14019052 Never hang on "connecting": time out the socket and fall back
iOS Safari can leave a blocked wss:// upgrade hanging without firing
onclose/onerror, so the badge sat on "connecting". The socket now times out a
slow handshake after 5s, reports at most one failure per attempt, and the app
commits to polling after a 6s grace period if the socket never opens.
2026-09-20 23:43:12 +00:00
matitos 8bb2836d7e Present REST polling as a normal live state
Some browsers (notably iOS Safari on an auth-gated page) abort the wss://
upgrade even though the server accepts it. Rather than showing a perpetual
"reconnecting", stop retrying after three failures, poll every 3s, and label
the badge "live (polling)" in green. The socket error is kept as a tooltip.
2026-09-20 13:47:42 +00:00
matitos bf7eda3f6a Fall back to REST polling when the WebSocket cannot connect
CI/CD / backend (pull_request) Successful in 6m6s
CI/CD / frontend (pull_request) Successful in 5m15s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
On some mobile networks/browsers the wss:// upgrade is blocked even though the
page loads (the server side is verified working: a browser-style handshake gets
101). After three socket failures the header now shows "polling (5s)" instead
of a misleading perpetual "reconnecting", since the 5s REST poll keeps all data
correct. The socket error handler also surfaces the browser's message.
2026-09-20 12:48:10 +00:00
matitos c63753e592 Stop caching index.html and speed up socket reconnect
CI/CD / backend (pull_request) Successful in 5m41s
CI/CD / frontend (pull_request) Successful in 5m18s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
Phones offer no easy hard-refresh, so a cached index.html kept serving an old
bundle after a deploy (the live feed showed "reconnecting"). index.html and the
SPA catch-all now send Cache-Control: no-store, while hashed /assets stay
immutable. Also retry the first socket reconnect after 1s (was 2s) and surface
the close code in the header so a failure is actionable on a phone.
2026-09-19 23:52:54 +00:00
matitos 9dc00eba95 Add trailing stops and parameter sweeps
CI/CD / backend (pull_request) Successful in 6m6s
CI/CD / frontend (pull_request) Successful in 5m17s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
Trailing stops: strategies can pass trailing_stop_pct to enter_long/enter_short.
advance_trailing_stop in app/engine/portfolio.py ratchets the stop with the price
(up for longs, down for shorts) and never loosens; the engine persists the
ratcheted level and the backtester applies the same logic. Position gains a
trailing_stop_pct column (additive migration). momentum exposes it as a param.

Parameter sweeps: app/backtest/sweep.py runs a cartesian grid through the same
backtester and ranks by return minus max drawdown. POST /api/sweep plus a
dashboard Parameter sweep panel.
2026-09-19 23:04:20 +00:00
matitos 2a88f55689 Make the API token fully optional
CI/CD / backend (pull_request) Successful in 5m36s
CI/CD / frontend (pull_request) Successful in 5m12s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
The deploy job hard-failed without CRYPTO_API_TOKEN, and /api/ws (which skips
Basic auth) relied on that token. Drop the requirement: the app now works with
no token at all, matching the backend guard that was always a no-op when unset.
When a token is configured it still protects /api and /api/ws; when it is not,
/api/ws is as open as the rest of the API, which the Traefik Basic auth still
guards for everything else. Adds tests for the tokenless API and WebSocket.
2026-09-19 14:31:42 +00:00
matitos 3e19612cc0 Serve /api/ws without Basic auth so the live feed connects
CI/CD / backend (pull_request) Successful in 5m58s
CI/CD / frontend (pull_request) Successful in 5m3s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
Browsers don't reliably replay Basic-auth credentials on a WebSocket upgrade,
so the dashboard's live feed was stuck on "reconnecting" (only the 5s REST
poll worked). Give /api/ws a higher-priority Traefik router that skips Basic
auth; the backend still requires API_TOKEN, which nginx injects on the
handshake. The deploy now fails closed unless CRYPTO_API_TOKEN is set.

Also: split the nginx /api/ws block so upgrade headers are only set there, and
add reconnect backoff (2s -> 30s) so a failing socket stops hammering.
2026-09-19 12:52:06 +00:00
matitos c500fb7572 Bitcoin favicon, more strategies, default timeframe 5m
CI/CD / backend (pull_request) Successful in 5m21s
CI/CD / frontend (pull_request) Successful in 5m4s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
- Add an SVG Bitcoin favicon and link it in index.html.
- New indicators: macd() and roc().
- Five new strategies: macd_trend, bollinger_reversion, donchian_breakout,
  ema_cross, momentum (plus the existing sma_cross, rsi_reversion).
- Default TIMEFRAME is now 5m (config, .env.example, compose, workflow, UI).
2026-09-18 20:03:30 +00:00
matitos 03dfa369e5 Risk controls, alerts, API token, more exchanges, presets
CI/CD / backend (pull_request) Successful in 6m18s
CI/CD / frontend (pull_request) Successful in 4m55s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped
- RiskManager halts + flattens on max daily loss / drawdown, caps position
  size and trades per day; adds a manual kill switch (POST /api/bot/kill).
- Telegram and webhook notifications on trades, errors and halts.
- Optional API bearer token on /api, injected server-side by the frontend
  nginx so the browser never sees it.
- Kraken and Coinbase market data (public); Coinbase live broker. Live on an
  unsupported exchange now errors instead of silently falling back to paper.
- Strategy presets backed by the StrategyConfig table (CRUD API + UI).
- Idempotent additive-column migration so existing SQLite databases upgrade in
  place (fixes the new strategy_configs.name column).
2026-09-18 19:26:29 +00:00
matitos 9c3bee87ac Crypto trading bot: engine, brokers, backtester, dashboard, deploy
CI/CD / backend (push) Successful in 5m18s
CI/CD / frontend (push) Successful in 5m2s
CI/CD / build (push) Successful in 34s
CI/CD / cleanup (push) Successful in 6s
CI/CD / deploy (push) Successful in 22s
FastAPI backend with a single-strategy async engine, paper and Binance
brokers, pure-python indicators, a backtester that shares the engine's
portfolio math, and a Vue dashboard with a live WebSocket feed. Adds the
Gitea Actions CI/CD workflow that deploys to Traefik via docker_default.
2026-09-18 17:02:33 +00:00