⚠ Denaro reale — leggi prima di procedere

Questo modulo tratta operazioni con denaro reale. Inizia sempre con un account paper trading (simulazione gratuita) e non portare mai in produzione una strategia non testata a fondo. I mercati finanziari comportano rischio di perdita totale del capitale investito.

Broker API per il trading automatico

Un broker API espone endpoint REST e WebSocket che permettono di inviare ordini, leggere lo stato del conto e ricevere dati di mercato in tempo reale via codice Python, senza nessuna interfaccia grafica.

📊 Alpaca Markets

Paper trading gratuito illimitato, commissioni zero su azioni USA, API REST e WebSocket ben documentate. Libreria ufficiale alpaca-py. Ideale per iniziare.

🌎 CCXT (Crypto)

Libreria Python unificata per 100+ exchange crypto (Binance, Coinbase, Kraken). Stesso codice su exchange diversi. Mercati aperti 24/7, anche nei weekend.

🇨🇪 Interactive Brokers

Broker professionale tramite libreria ib_insync. Accesso a tutti i mercati mondiali: azioni, futures, opzioni, forex. Curva di apprendimento più ripida.

🔄 Flusso tipico di un bot

1→ Scarica dati recenti   2→ Calcola indicatori   3→ Genera segnale   4→ Verifica posizione attuale   5→ Invia ordine se necessario   6→ Attendi il prossimo tick

Setup e autenticazione Alpaca

Dopo aver creato un account gratuito su alpaca.markets, in Paper Trading → API Keys genera e copia le credenziali. Vanno sempre nelle variabili d’ambiente — mai scritte direttamente nel codice sorgente.
Il metodo piΓΉ sicuro Γ¨ usare funzione integrata secrets di Colab (icona a chiave key) e aggiungere i nomi API_KEY e SECRET_KEY, ad esempio, attribuendo loro come valori le credenziali fornite da Alpaca.

Innanzitutto occorre installare le librerie necessarie.

In:
!pip install alpaca-trade-api !pip install alpaca-py

Importeremo quindi classi e metodi necessari.

In:
import alpaca from alpaca.trading.client import TradingClient from alpaca.data.historical import StockHistoricalDataClient from alpaca.data.requests import StockBarsRequest from alpaca.data.timeframe import TimeFrame from datetime import datetime, timedelta from google.colab import userdata # πŸ” CONFIG API_KEY = userdata.get("ALPACA_API_KEY") SECRET_KEY = userdata.get("ALPACA_SECRET_KEY") # Client per il trading (paper=True = simulazione) trading = TradingClient(API_KEY, SECRET_KEY, paper=True) account = trading.get_account() print(f"Portafoglio: ${float(account.portfolio_value):,.2f}") print(f"Cash: ${float(account.cash):,.2f}") print(f"Buying power: ${float(account.buying_power):,.2f}")
Out:
Portafoglio: $100,006.77 Cash: $99,746.91 Buying power: $199,198.77
Consiglio

Evitare file .py con chiavi in chiaro, scriverle direttamente nel notebook (se pubblico), caricare chiavi su GitHub. Una API key esposta su GitHub pubblico viene trovata e usata da bot automatici in pochi minuti.

Il seguente Γ¨ un test rapido per diagnosticare i problemi.

In:
def diagnostica(): print("πŸ” DIAGNOSTICA ALPACA") # 1. Test connessione tc = TradingClient(API_KEY, SECRET_KEY, paper=True) try: acc = tc.get_account() print(f"βœ… API funzionante - Account: {acc.account_number}") print(f"πŸ’° Cash: ${float(acc.cash):.2f}") except Exception as e: print(f"❌ Errore API: {e}") return # 2. Test dati storici dc = StockHistoricalDataClient(API_KEY, SECRET_KEY) # Prova diversi intervalli for ore in [8, 24, 48, 72]: req = StockBarsRequest( symbol_or_symbols="AAPL", timeframe=TimeFrame.Minute, start=datetime.now() - timedelta(hours=ore) ) resp = dc.get_stock_bars(req) print(f"Ultime {ore} ore: {len(resp.df)} barre") # 3. Orario corrente clock = tc.get_clock() print(f"\nπŸ• Ora server: {clock.timestamp}") print(f"πŸ“ˆ Mercato aperto: {clock.is_open}") print(f"πŸ”œ Prossima apertura: {clock.next_open}") print(f"πŸ”š Prossima chiusura: {clock.next_close}") diagnostica()
Out:
πŸ” DIAGNOSTICA ALPACA βœ… API funzionante - Account: PA3X7GHV0YZE πŸ’° Cash: $99746.91 Ultime 8 ore: 227 barre Ultime 24 ore: 876 barre Ultime 48 ore: 1584 barre Ultime 72 ore: 1716 barre πŸ• Ora server: 2026-04-08 08:52:35.853742-04:00 πŸ“ˆ Mercato aperto: False πŸ”œ Prossima apertura: 2026-04-08 09:30:00-04:00 πŸ”š Prossima chiusura: 2026-04-08 16:00:00-04:00

Inviare e gestire ordini

Alpaca supporta tutti i tipi di ordine visti nel modulo 1. I pattern più utili in un bot sono il market order per l’entrata rapida, il limit order per l’entrata precisa e il trailing stop per proteggere i profitti senza sorveglianza continua.

In:
from alpaca.trading.requests import ( MarketOrderRequest, LimitOrderRequest, TrailingStopOrderRequest ) from alpaca.trading.enums import OrderSide, TimeInForce # ── 1. Market order (esecuzione immediata al prezzo corrente) ─ o = trading.submit_order(MarketOrderRequest( symbol="AAPL", qty=10, side=OrderSide.BUY, time_in_force=TimeInForce.DAY )) print(f"Market order: {o.id} β€” status: {o.status}") # ── 2. Limit order (compra solo se prezzo scende a 148) ─────── trading.submit_order(LimitOrderRequest( symbol="AAPL", qty=5, side=OrderSide.BUY, limit_price=148.00, time_in_force=TimeInForce.GTC # Good Till Cancelled )) # ── 3. Trailing stop (vende se prezzo scende del 2% dal max) ─ trading.submit_order(TrailingStopOrderRequest( symbol="AAPL", qty=10, side=OrderSide.SELL, trail_percent=2.0, time_in_force=TimeInForce.GTC # Added missing time_in_force )) # ── 4. Visualizza tutti gli ordini aperti ───────────────────── aperti = trading.get_orders() for x in aperti: print(f"{x.symbol} {x.side} qty={x.qty} [{x.status}]") # ── 5. Cancella un ordine ───────────────────────────────────── trading.cancel_order_by_id(o.id)

Monitorare e chiudere posizioni

In:
# Leggi tutte le posizioni aperte positions = trading.get_all_positions() for p in positions: pnl = float(p.unrealized_plpc) * 100 seg = "+" if pnl > 0 else "" print( f"{p.symbol:<6} qty={p.qty:>6}" f" valore=${float(p.market_value):8.2f}" f" P&L={seg}{pnl:.2f}%" ) # Helper: controlla se hai una posizione su un simbolo def ha_posizione(symbol) -> bool: try: trading.get_open_position(symbol) return True except: return False # Fix: Cancel any pending sell orders for AAPL before attempting to close the position open_orders = trading.get_orders() # Get all open orders (defaults to open) for order in open_orders: if order.symbol == "AAPL" and order.side == OrderSide.SELL: print(f"Cancelling pending sell order for {order.symbol} with ID: {order.id}") trading.cancel_order_by_id(order.id) # Chiudi una posizione specifica trading.close_position("AAPL") # Panic button: chiudi tutto e cancella ordini pendenti trading.close_all_positions(cancel_orders=True)
Out:
AAPL qty= 1 valore=$ 258.40 P&L=+2.61% [{ 'body': { 'asset_class': , 'asset_id': UUID('b0b6dd9d-8b9b-48a9-ba46-b9d54906e415'), 'canceled_at': None, 'client_order_id': 'a8742490-5dd1-4d98-8e8e-30fc1b3f8297', 'created_at': datetime.datetime(2026, 4, 8, 14, 19, 1, 713120, tzinfo=TzInfo(0)), 'expired_at': None, 'expires_at': datetime.datetime(2026, 4, 8, 20, 0, tzinfo=TzInfo(0)), 'extended_hours': False, 'failed_at': None, 'filled_at': None, 'filled_avg_price': None, 'filled_qty': '0', 'hwm': None, 'id': UUID('69cc825f-5ea9-4875-b997-4c2efd690e64'), 'legs': None, 'limit_price': None, 'notional': None, 'order_class': , 'order_type': , 'position_intent': , 'qty': '1', 'ratio_qty': None, 'replaced_at': None, 'replaced_by': None, 'replaces': None, 'side': , 'status': , 'stop_price': None, 'submitted_at': datetime.datetime(2026, 4, 8, 14, 19, 1, 713120, tzinfo=TzInfo(0)), 'symbol': 'AAPL', 'time_in_force': , 'trail_percent': None, 'trail_price': None, 'type': , 'updated_at': datetime.datetime(2026, 4, 8, 14, 19, 1, 713825, tzinfo=TzInfo(0))}, 'order_id': None, 'status': 200, 'symbol': 'AAPL'}]

Bot di trading automatico completo

Un bot di produzione deve gestire errori di rete, rispettare gli orari di mercato, fermarsi in caso di perdite eccessive e loggare ogni operazione su file. Ecco un’implementazione robusta della strategia SMA Crossover.

In:
import time import logging from datetime import datetime, timedelta # πŸ” CONFIG API_KEY = userdata.get("ALPACA_API_KEY") SECRET_KEY = userdata.get("ALPACA_SECRET_KEY") logging.basicConfig(level=logging.INFO) class RealBot: def __init__(self, symbol="AAPL"): self.symbol = symbol self.tc = TradingClient(API_KEY, SECRET_KEY, paper=True) self.dc = StockHistoricalDataClient(API_KEY, SECRET_KEY) self.fast = 20 self.slow = 50 self.position = False self.entry_price = None self.risk_per_trade = 0.01 # 1% # πŸ“Š DATI (CORRETTO) def get_data(self): try: # Richiedi 5 giorni di dati per avere abbastanza storia req = StockBarsRequest( symbol_or_symbols=self.symbol, timeframe=TimeFrame.Minute, start=datetime.now() - timedelta(days=5), limit=500 # Limita a 500 barre ) response = self.dc.get_stock_bars(req) # METODO CORRETTO per estrarre i dati if response.df.empty: logging.warning("Nessun dato ricevuto") return None # Converti MultiIndex in DataFrame semplice df = response.df.droplevel(0) # Rimuove il livello del simbolo df = df.reset_index() # Resetta l'indice df = df.set_index('timestamp') # Usa timestamp come indice if len(df) < self.slow: logging.warning(f"Dati insufficienti: {len(df)} righe, serve almeno {self.slow}") return None # Calcola SMA df["SMA_fast"] = df["close"].rolling(self.fast).mean() df["SMA_slow"] = df["close"].rolling(self.slow).mean() # RSI delta = df["close"].diff() gain = delta.clip(lower=0) loss = -delta.clip(upper=0) avg_gain = gain.rolling(14).mean() avg_loss = loss.rolling(14).mean() rs = avg_gain / avg_loss df["RSI"] = 100 - (100 / (1 + rs)) return df except Exception as e: logging.error(f"Errore get_data: {e}") return None # 🎯 SEGNALE def signal(self, df): if df is None or len(df) < 2: return "HOLD" f = df["SMA_fast"] s = df["SMA_slow"] rsi = df["RSI"] # Verifica che non ci siano NaN if f.isna().iloc[-1] or s.isna().iloc[-1] or rsi.isna().iloc[-1]: return "HOLD" f_now, f_prev = f.iloc[-1], f.iloc[-2] s_now, s_prev = s.iloc[-1], s.iloc[-2] rsi_now = rsi.iloc[-1] if f_prev < s_prev and f_now > s_now and rsi_now < 70: return "BUY" if f_prev > s_prev and f_now < s_now: return "SELL" return "HOLD" # πŸ’° SIZE DINAMICA def position_size(self, price): acc = self.tc.get_account() capital = float(acc.equity) risk_amount = capital * self.risk_per_trade stop_loss_pct = 0.02 qty = int(risk_amount / (price * stop_loss_pct)) return max(qty, 1) # πŸš€ LOOP def run(self): logging.info(f"Bot reale avviato per {self.symbol}") logging.info(f"Parametri: SMA{self.fast} / SMA{self.slow}") ciclo = 0 while True: ciclo += 1 try: logging.info(f"---- CICLO {ciclo} ----") # Verifica se il mercato Γ¨ aperto clock = self.tc.get_clock() logging.info(f"Mercato aperto: {clock.is_open}") if not clock.is_open: logging.info("Mercato chiuso - attesa 5 minuti") time.sleep(300) # 5 minuti quando chiuso continue # Ottieni dati df = self.get_data() if df is None: logging.warning("Nessun dato disponibile") time.sleep(60) continue logging.info(f"Dati ricevuti: {len(df)} righe") sig = self.signal(df) price = df["close"].iloc[-1] logging.info(f"SEGNALE: {sig} | PREZZO: {price:.2f}") # Mostra anche gli indicatori per debug logging.info(f"SMA_fast: {df['SMA_fast'].iloc[-1]:.2f}, SMA_slow: {df['SMA_slow'].iloc[-1]:.2f}") logging.info(f"RSI: {df['RSI'].iloc[-1]:.2f}") logging.info(f"Posizione aperta: {self.position}") # 🟒 BUY if sig == "BUY" and not self.position: qty = self.position_size(price) if qty > 0: order = MarketOrderRequest( symbol=self.symbol, qty=qty, side=OrderSide.BUY, time_in_force=TimeInForce.DAY ) self.tc.submit_order(order) self.position = True self.entry_price = price logging.info(f"🟒 BUY {qty} @ {price}") else: logging.warning("QuantitΓ  zero, ordine non eseguito") # πŸ”΄ SELL (crossover) elif sig == "SELL" and self.position: self.tc.close_position(self.symbol) self.position = False logging.info("πŸ”΄ SELL (crossover)") # πŸ›‘ STOP LOSS / TAKE PROFIT if self.position and self.entry_price: if price <= self.entry_price * 0.98: self.tc.close_position(self.symbol) self.position = False logging.info(f"πŸ›‘ STOP LOSS a {price:.2f} (entry: {self.entry_price:.2f})") elif price >= self.entry_price * 1.03: self.tc.close_position(self.symbol) self.position = False logging.info(f"πŸ’° TAKE PROFIT a {price:.2f} (entry: {self.entry_price:.2f})") time.sleep(60) # Controlla ogni minuto except Exception as e: logging.error(f"Errore nel ciclo: {e}") import traceback traceback.print_exc() time.sleep(60) # === ESECUZIONE CON TEST PRELIMINARE === if __name__ == "__main__": print("Avvio bot...") # Test rapido di connessione bot_test = RealBot("AAPL") try: acc = bot_test.tc.get_account() print(f"βœ… Connessione riuscita! Account: {acc.account_number}") print(f"πŸ’° Equity: ${float(acc.equity):.2f}") # Test dati print("\nπŸ“Š Test recupero dati...") df_test = bot_test.get_data() if df_test is not None: print(f"βœ… Dati recuperati: {len(df_test)} righe") print(df_test[['close', 'SMA_fast', 'SMA_slow', 'RSI']].tail()) else: print("❌ Problema nel recupero dati") # Avvia bot print("\nπŸš€ Avvio bot in modalitΓ  paper trading...") bot_test.run() except Exception as e: print(f"❌ Errore di connessione: {e}")
Out:
Avvio bot... βœ… Connessione riuscita! Account: PA3X7GHV0YZE πŸ’° Equity: $100005.26 πŸ“Š Test recupero dati... βœ… Dati recuperati: 500 righe close SMA_fast SMA_slow RSI timestamp 2026-04-06 19:04:00+00:00 259.1450 259.115905 259.078150 56.196176 2026-04-06 19:05:00+00:00 258.9901 259.113410 259.086352 48.740347 2026-04-06 19:06:00+00:00 258.9800 259.110415 259.092152 41.549296 2026-04-06 19:07:00+00:00 258.9400 259.106415 259.092850 38.513514 2026-04-06 19:08:00+00:00 258.8600 259.096415 259.089250 26.206897 πŸš€ Avvio bot in modalitΓ  paper trading...

Sicurezza operativa

Un bot non supervisionato può perdere denaro molto più velocemente di quanto tu possa immaginare. Queste misure non sono optional — sono il minimo indispensabile per andare live in modo responsabile.

MisuraCome implementarlaPriorità
Credenziali sicure API key in .env, mai nel codice. .env nel .gitignore sempre Critica
Paper trading first Almeno 30 giorni di simulazione con risultati stabili prima del live Critica
Circuit breaker Ferma e chiudi tutto se la perdita giornaliera supera la soglia prefissata Critica
Gestione eccezioni Try/except su ogni chiamata API, log su file di tutti gli errori Alta
Limite ordini/giorno Contatore giornaliero con soglia massima per evitare loop impazziti Alta
Alert notifiche Email o Telegram in caso di errori critici o drawdown anomalo Alta
Orari di mercato Controlla clock.is_open prima di ogni operazione Media
Logging su file Ogni trade salvato su CSV con timestamp, simbolo, prezzo, P&L Media

Checklist pre-produzione

Prima di passare da paper trading a soldi reali, verifica ogni punto. Non saltare niente — specialmente le prime tre voci.

  • La strategia ha un backtest out-of-sample positivo su almeno 2 anni di dati
  • Il paper trading mostra risultati stabili per almeno 30 giorni di calendario
  • Il circuit breaker è implementato, testato e funzionante
  • Le credenziali sono in .env e il file è in .gitignore
  • Il logging su file è attivo e i log sono accessibili per l’audit
  • È configurato un alert (email o Telegram) per errori critici
  • Il bot rispetta gli orari di mercato (clock.is_open)
  • Il codice è in un repository Git con history pulita
  • Hai definito il budget massimo che sei disposto a rischiare
  • Hai letto e compreso i Terms of Service del broker
Verifica la comprensione
Qual è la ragione principale per testare con il paper trading prima di andare live con soldi reali?
A Il paper trading è obbligatorio per legge nei mercati europei
B Verifica il comportamento del codice reale in condizioni di mercato reale, senza rischio finanziario
C Il backtest su dati storici è sufficiente per garantire profitti futuri
D Alpaca richiede 30 giorni di paper trading prima di sbloccare il live
PROGETTO FINALE Bot completo: dalla strategia al paper trading

Costruisci un bot di paper trading end-to-end che integra tutto ciò che hai imparato nel corso. Usa Alpaca in modalità paper (gratuito, nessuna registrazione bancaria).

  • Implementa la strategia RSI(14) + filtro SMA50: compra quando RSI < 35 e Close > SMA50
  • Aggiungi position sizing: rischia al massimo l’1% del capitale per singolo trade
  • Implementa circuit breaker: ferma tutto se la perdita giornaliera supera il 2%
  • Salva ogni trade su un file CSV: timestamp, simbolo, qty, prezzo di entrata, P&L
  • Bonus: invia un messaggio Telegram quando il bot esegue un ordine
  • Bonus avanzato: sostituisci la strategia SMA con il modello ML del modulo 5
🎉

Hai completato il corso PyTrading!

Sei partito dai fondamenti dei mercati finanziari e sei arrivato a costruire un bot di trading automatico in Python. Hai imparato a scaricare e analizzare dati, implementare indicatori tecnici, fare backtesting rigoroso, applicare il Machine Learning e connetterti a un broker API reale.

Il prossimo passo è tuo: porta una strategia in paper trading, misura le performance per 30 giorni, e poi decidi se vale la pena passare al live.

← Torna alla home