File size: 8,534 Bytes
fc115d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# HF Client-Only Fix Log
Date: 2026-03-19

## Problem
`chen470/drl-trading-bot-dev2` HF Space crashed on load with `KeyError: 'close'` at
`app.py line 1837` because `load_real_market_data` was calling `/api/market` which
returns a single price dict (not OHLCV candlestick data).

Additional issues: multiple server-side imports (`src.features.whale_wallet_registry`,
`subprocess` bot control, `storage.log_trade`, local file deletion) that crash or
silently corrupt state on HF where only `src.ui` and `src.data.storage` are available.

## Fixes Applied

### `src/ui/api_server.py`
- Added `GET /api/ohlcv?symbol=&interval=&limit=` endpoint β€” fetches real candlestick
  data from Binance `/api/v3/klines` and returns `[{time, open, high, low, close, volume}, ...]`

### `src/ui/app.py`
1. **`IS_CLIENT_MODE` flag** β€” `bool(os.environ.get('API_SERVER_URL'))`, true on HF
2. **`load_real_market_data`** β€” now calls `/api/ohlcv` (returns proper DatetimeIndex
   DataFrame with OHLCV columns); fixes the line 1837 `df['close']` crash
3. **`load_trading_log`** β€” uses `GET /api/trades` in client mode, local storage otherwise
4. **`get_trading_state`** β€” uses `GET /api/state` + `GET /api/trades` in client mode;
   all `src.features.whale_wallet_registry` imports moved to `_load_whale_alerts_local()`
   (server-only helper with `try/except ImportError` guard)
5. **Trading Controls** β€” subprocess calls (pgrep/pkill/Popen for bot start/stop) and
   `storage.log_trade()` disabled in client mode; shows info message instead
6. **Clear Trade Log** β€” local file deletion guarded behind `not IS_CLIENT_MODE`
7. **Live Portfolio tab** β€” uses `load_trading_log()` (API-aware) instead of
   `storage.get_trades()` directly; bot online-status inferred from trade timestamps
8. **Backtest tab** β€” moved UI from inside `tab_testnet` (wrong tab) to `tab_backtest`;
   shows graceful "not available in client mode" message on HF

## Verification
- `python3 -c "import src.ui.app"` β€” no errors (only expected Streamlit warnings)
- `grep "from src\.(backtest|brain|env|features|models|api)"` β€” only guarded occurrences
- HF container logs after factory restart: ZERO errors, clean startup in ~80s

---

# Live Chart "No market data available" Fix
Date: 2026-03-19

## Problem
The Live Chart tab showed "No market data available" even though `/api/ohlcv` works.

## Root Cause
`load_real_market_data` had a bare `except Exception: pass` that silently swallowed
all errors. On HF the SDK is `streamlit` (no Flask server, only `app_file: src/ui/app.py`),
so there is NO local Flask server at `localhost:5001`. The HTTP request always failed,
the exception was swallowed, and the function returned an empty DataFrame.

## Fix (`src/ui/app.py` β€” `load_real_market_data`)
1. **Added logging** β€” replaced `except Exception: pass` with `_logger.warning(...)` so
   failures are visible in HF container logs
2. **Direct Binance fallback** β€” after the Flask API attempt fails, the function now
   directly calls `https://data-api.binance.vision/api/v3/klines` (the same endpoint
   the Flask server itself uses, no auth required) and parses the raw Binance klines
   format into the same DataFrame schema. This works regardless of whether Flask is up.

## Tests Added (`tests/test_api/test_ohlcv.py` β€” 27 tests, all passing)
- `/api/ohlcv` endpoint: all symbols (BTCUSDT, ETHUSDT, SOLUSDT), all intervals
  (1m, 5m, 15m, 30m, 1h, 4h, 1d), time-in-seconds validation, error handling
- `load_real_market_data`: returns non-empty DataFrame with correct columns/index,
  falls back to direct Binance when Flask unavailable, handles total failure gracefully
- Chart rendering: does not crash with valid data, returns "No market data available"
  for empty DataFrame, embeds historical candle data before WebSocket connects

## Deploy
- Commit: `43aa9d33` pushed to `hf-dev2 hf-clean:main`
- Factory restart at 2026-03-19 19:45Z
- Build logs: DONE (no errors)
- Run logs: clean Streamlit startup on port 8501, zero errors

---
## 2026-03-19 β€” Market Analysis / Agent Status / Testnet Fixes

### Issues Fixed

**Issue 1: Market Analysis "Unable to load"**
- Added non-200 HTTP status code handling in `render_market_analysis_fragment`
  (was silently returning `{}`, now shows an error card with HTTP status)

**Issue 2: Agent Status "Model: Not found" / "0.0% Win Rate"**
- Root cause: `model_path.exists()` always False on HuggingFace (model file not deployed to HF Space)
- Fix: In `IS_CLIENT_MODE`, call `/api/model` endpoint instead of checking local filesystem
  β€” returns `model_exists`, `model_date`, `win_rate`, `total_return`, `total_trades` from server
- Model status and trade stats now reflect actual server-side data

**Issue 3: Testnet "Cannot reach API server"**
- Added `if tn_resp.status_code == 200:` check before `.json()` call
  to handle non-200 responses cleanly (previously would throw on 404/500)

**Issue 4: Short timeouts causing "Current Price: $0.00" / stale data**
- Increased all `timeout=1` to `timeout=5` for API calls in fragments:
  - `render_sidebar_metrics_fragment` (state)
  - `render_position_fragment` (state, trades)
  - `render_agent_status_fragment` (state, trades)
  - `render_position_fragment` trades call (was timeout=2, now 5)

### E2E Tests Added
- `tests/test_integration/test_e2e_api.py` β€” 14 `@pytest.mark.e2e` tests
  - `/api/state`: non-empty dict, has assets/balance, position fields
  - `/api/market`: price data, regime/whale present, app.py parse simulation
  - `/api/testnet/status`: HTTP 200, all required keys, parse simulation
  - `/api/ohlcv`: 500 candles, candle structure validation
  - `/api/model`: win_rate, total_trades, model_exists fields

### Deploy
- Branch: hf-clean β†’ pushed to hf-dev2/main (commit 08ab9ef)
- Factory restart triggered, container started CLEAN (zero errors)

---

## No-Mock-Data Audit & Fix β€” 2026-03-19

### Policy
All data points in the UI must be real. No fake/generated/padded data.

### Files Changed
- `src/ui/api_server.py`
- `src/ui/app.py`
- `src/ui/testnet_server.py`
- `src/ui/testnet_client.py`

### Fixes Applied

#### 1. Fake Whale Alerts (CRITICAL)
**api_server.py lines 128-162**: Removed 35-line block that generated up to 50 fake whale transactions with `random.uniform` amounts, `random.choice` chains, `random.randbytes` wallet addresses, and `random.randint` timestamps. Disguised as "seamless backfill for rich visual experience".

**app.py `_load_whale_alerts_local()`**: Removed identical fake generator. Removed `import random as _random`.

After fix: whale alerts show only real on-chain data from `data/whale_wallets/*.json`. If none available, shows empty list.

#### 2. Hardcoded Initial Capital ($5k/asset β†’ state balance)
Removed `initial_capital = max(len(raw_assets), 1) * 5000 if raw_assets else 20000` pattern from:
- `api_server.py` /api/state endpoint (was overriding `total_balance` with fake value)
- `app.py` asset view path
- `app.py` global view path  
- `app.py` sidebar Agent Status section
- `app.py` Live Portfolio tab (was `4 * 5000 = $20,000`)

After fix: balance uses `state.get('total_balance', state.get('balance'))` β€” real stored state only.

#### 3. Hardcoded 10000 as Initial Capital for Return %
- `api_server.py` /api/model: `total_return` now `None` (cannot compute without real initial capital)
- `api_server.py` /api/testnet: `pnl_pct` and `pnl_usdt` now `None`
- `app.py` Live Portfolio tab: equity curve uses absolute PnL points (not % of fake capital)
- `app.py` Live Portfolio tab: Realized PNL and Open PNL cards now show absolute `$` amounts
- `app.py` per-asset table: PnL% column shows `β€”` (dollar column still shows real value)
- `app.py` per-asset table: Best/Worst columns show absolute `$` not fake `%`
- `app.py` testnet performance tab: Total Return shows "N/A"
- `app.py` sidebar: `portfolio_balance` default of 10000 removed, shows `β€”` if unavailable
- `testnet_server.py`: P&L % metric shows "N/A"
- `testnet_client.py`: JS `initialValue = 10000` removed, P&L % shows "N/A"

#### 4. Manual Trade Log Balance
`app.py` Open Long / Open Short / Close Position buttons: `state.get('balance', 10000)` β†’ `state.get('balance')` β€” no fake 10000 logged in trade records.

### Verification
```
grep -r "random\.uniform|random\.choice|needed_mock|initial_capital|backfill.*gap" src/ui/
# β†’ No matches found
```

### Deployment
- Commit: `faa23b1`
- Branch: `hf-clean` β†’ force pushed to `hf-dev2/main`
- Space status: RUNNING, sha matches, domain READY