# AGENTS.md — charter_core

> **Package**: `charter_core` (FASE 1-4 consolidamento Charter)
> **Path**: `G:\AI TRADING ENGINE\charter_core\`
> **Version**: 1.1.0 (bumpato in FASE 3 con charter_engine, FASE 4 con pyproject.toml)
> **Creato**: 2026-07-14
> **Owner**: Mattia Antoniucci + Mavis (consolidamento)
> **Install**: `pip install -e "G:\AI TRADING ENGINE"` (FASE 4)

## Ruolo

Singolo punto di verità per le **regole Charter** (business rules) del
Trading Engine AI. Prima di questo package, le regole erano sparse in
5+ file del workspace. Ora vivono qui, in 4 moduli coesi.

## Mappa moduli

| Modulo | Cosa contiene | Esempio export |
|---|---|---|
| `charter_config` | SETUPS (3) + CHARTER (backtest) + globali | `SETUPS`, `CHARTER`, `CLOSING_HOURS` |
| `cd_types` | 8 tipi Candle Direction + helper | `CDType`, `parse_cd_mask`, `compute_cd_from_row` |
| `indicators` | Parametri indicatori (BB, ROC, ATR, EMA, ADX) | `BB_PARAMS`, `ADX_PARAMS` |
| `paletti` | 14 "paletti" Mattia (regole business hard) | `PALETTI`, `PalettiCategory` |
| `charter_engine` (FASE 3) | API riusabile (Bot, Setup, Signal, BybitClient) + helper Pine-faithful | `Bot`, `Setup`, `Signal`, `BybitClient` |

## Vincoli Charter (estratti dai paletti)

| Vincolo | Valore | Paletto |
|---|---|---|
| Fee Pine IMPLICITA | 0.06% per lato (0.0006) | P003 |
| Leva Charter | 3x per TUTTI gli asset | P004 |
| TP split | 50/50 a +3% / +5% | P005 |
| SL | ATR 2x clampato a -3% | P006 |
| Regime filter | EMA50 + ADX>20 obbligatorio | P007 |
| Max posizioni | 5 (deroga 12/07) | P008 |
| Candela segnale | sempre [-2], mai [-1] | P010 |
| Leva bypass | solo se già 3x | P014 |
| No media-up | hard rule post 12/07 | P001 |
| No double-buy | hard rule post 12/07 | P002 |
| Charter primary | AI Enhancer NON riduce size | P012 |
| SL nativo Bybit V5 | via set_trading_stop | P013 |
| set_leverage prima | di create_market_order | P011 |
| Anti-doppia candela | state.last_signal_bar check | P009 |

## Quando usarlo

**SEMPRE** quando un sub-repo (mavis, solver, verifier) ha bisogno di
una regola Charter.

```python
# Corretto (import da charter_core)
from charter_core import SETUPS, CHARTER, CDType, BB_PARAMS
zec = next(s for s in SETUPS if s["name"] == "ZEC_4H")
fee = CHARTER["commission_pct"]  # 0.0006, NON 0.0010

# Sbagliato (magic number locale)
FEE = 0.0010  # ❌ viola P003
SETUP_LEVERAGE = 5  # ❌ viola P004
```

## Quando NON usarlo

- Codice che NON è Charter-related (es. utilities generiche)
- Script one-shot che non vengono importati altrove
- File di configurazione runtime (es. Bybit_new.env)

## Comandi rapidi (per un agente)

```powershell
# Import + verifica
cd "G:\AI TRADING ENGINE"
python -c "from charter_core import *; print('OK')"

# Smoke test
python -m charter_core.tests.test_smoke

# Report paletti in markdown
python -c "from charter_core import paletti; print(paletti.format_paletto_report())"

# Conteggio
python -c "from charter_core import total_paletti_count; print(f'Paletti: {total_paletti_count()}')"
```

## Sub-moduli nel dettaglio

### `charter_config`

Contiene:
- `SETUPS`: list di 3 dict (ZEC_4H, AERO_4H, DASH_4H) Charter primary
- `SETUPS_BY_NAME`, `SETUPS_BY_SYMBOL`: indici di lookup
- `get_setup(name)`, `get_setup_by_symbol(symbol)`: helper
- `CHARTER`: dict per backtest (fee 0.0006, TP 50/50, leverage 3x)
- `get_charter()`: helper
- `GLOBAL_CONSTANTS`: MAX_OPEN_TRADES_PORTFOLIO, CLOSING_HOURS, paths
- `MAX_OPEN_TRADES_PORTFOLIO = 5` (deroga Mattia 12/07)
- `CLOSING_HOURS = [2, 6, 10, 14, 18, 22]` (Europe/Rome)

### `cd_types`

Contiene:
- `CDType` IntEnum (CLL=0, CLS=1, CSL=2, CSS=3, DLL=4, DLS=5, DSL=6, DSS=7)
- `CD_BIT_NAMES`, `CD_FULL_NAMES`, `CD_DIMENSIONS`
- `parse_cd_mask(str) -> list[int]`: converte mask 8-bit in lista LSB-first
- `cd_idx_to_name(int)`, `cd_name_to_idx(str)`: lookup
- `is_cd_active_in_mask(cd_idx, mask_str) -> bool`
- `active_cds_in_mask(mask_str) -> list[CDType]`
- `compute_cd_from_row(row) -> int`: calcola CD di una candela dati 3 segni

Convenzione bit: bit 0 = CLL (rightmost char della mask string).

### `indicators`

Contiene SOLO i parametri Charter (NON il calcolo, che vive nei sub-repo).
- `BB_PARAMS`: length=55, mult=1.0
- `ROC_PARAMS`: length=36
- `ATR_PARAMS`: length=16, sl_atr_mult=2.0, sl_clamp_min/max=-0.03
- `EMA50_PARAMS`: span=50, regime_filter_side (LONG: above, SHORT: below)
- `ADX_PARAMS`: period=14, min_threshold=20.0
- `get_indicator_params(name)` helper
- `compute_cd_from_row` re-export da `cd_types`

### `paletti`

14 paletti hard documentati con:
- `id`: P001-NO_MEDIA_UP, P002-NO_DOUBLE_BUY, ecc.
- `category`: POSITION_SIZING / RISK_MANAGEMENT / SIGNAL_GENERATION / EXECUTION / STATE_MANAGEMENT / COMPLIANCE
- `description`: spiegazione human-readable
- `file_ref`: puntatore al file originale
- `bug_origin`: BUG che ha generato il paletto (se applicabile)

Funzioni:
- `is_paletto_violated(id, context) -> bool`: stub (validazione reale nei sub-repo)
- `format_paletto_report() -> str`: report markdown

### `charter_engine` (FASE 3)

API riusabile ad alto livello. NON sostituisce live_engine.py: lo
affianca per casi d'uso custom (CLI, notebook, paper trading, test).

**Componenti**:

- `Setup` (dataclass): rappresenta 1 setup Charter con tutti i
  parametri (name, symbol, mask, sizing, TP/SL, leverage).
  - `Setup.from_dict(d)` per costruire da dict
  - `setup.to_dict()` per serializzare
  - `setup.active_cd_types` property: lista CDType attivi nella mask
  - `setups_from_list(lst)` helper per lista di dict

- `Signal` (dataclass): output di detect_signal (LONG/SHORT, entry, atr,
  timestamp, regime_ok, regime_msg, bb_break, roc_dir).
  - `signal.is_long` / `signal.is_short` properties
  - `signal.tp_levels(sl_clamp_min=-0.03)` -> (tp1, tp2, sl)

- `BybitClient` (wrapper): API semplificata sopra bybit_demo_client
  - `BybitClient(client=None)`: se client=None, prova a importare
    bybit_demo_client.BybitDemoClient (lato live)
  - `is_available` property
  - `get_qty_for_setup(setup, current_price)`: size Charter
  - `set_charter_leverage(setup)`: imposta leva (con bypass)
  - `get_open_position(symbol)`: posizione aperta o None
  - `place_charter_entry(signal, setup)`: 4-step entry
    (set_leverage + market + 2 limit + SL nativo Bybit V5)
  - Delega automatica di metodi non wrappati via `__getattr__`

- `Bot` (classe principale): orchestra setup + segnali + ordini
  - `Bot(client, setups, state=None)`
  - `bot.get_setup(name)`, `bot.get_status()`
  - `bot.process_setup(name, ohlcv=None)`: ritorna Signal o None
  - `bot.place_entry(signal)`: delega al client

**Helper funzioni pure (Pine-faithful)**:

- `compute_indicators_pine_faithful(df, setup) -> df`
  Calcola BB, ROC, ATR Wilder RMA, EMA50, ADX (placeholder 25.0),
  CD per ogni candela. Richiede pandas/numpy.

- `detect_signal_pine_faithful(df, setup) -> Signal | None`
  Logica: CD match + BB breakout + ROC direction. Candela [-2] sempre.

- `check_regime_pine_faithful(df, signal) -> (ok, msg)`
  Regime filter: ADX > 20 + EMA50 side-aligned.

**Quando usarlo**:
- Script custom che vogliono usare Charter senza tutto il live setup
- Test unitari (con MockBybitClient, no API keys reali)
- Notebook Jupyter per esplorare Charter
- CLI custom (es. per backtest one-shot)
- Paper trading (DRY-RUN con --confirm-live disattivato)

**Quando NON usarlo**:
- Per il Charter LIVE con MIL dynamic sizing, signal enhancer, state
  management: usa live_engine.py che ha tutta la logica specifica
- Per sostituire live_engine in produzione serve una migrazione
  graduale (FASE 4+, opzionale)

## Se stai lavorando qui

1. **Rispetta** i paletti (vedi tabella sopra). Qualsiasi violazione è un bug.
2. **Modifica parametri SOLO qui** — mai duplicare magic number nei sub-repo.
3. **Testa** dopo ogni modifica con `python -m charter_core.tests.test_smoke`.
4. **Aggiungi paletti** se ne scopri di nuovi (es. durante un bug investigation).
5. **Aggiorna AGENTS.md** se aggiungi un nuovo modulo al package.
6. **Cross-linka** se modifichi Charter compliance: aggiorna anche:
   - `GIT_REPOS/trading-engine-mavis/AGENTS.md` (MEMORY compliance section)
   - `GIT_REPOS/trading-engine-solver/AGENTS.md` (backtest Charter dict)
   - `GIT_REPOS/trading-engine-verifier/docs/INDEX.md` (BUG list)
7. **Mai** rimuovere un paletto. Se ne scopri uno sbagliato, depreca con
   `id: "DEPRECATED-..."` e crea un nuovo paletto che lo sostituisce.
