AG
TR

// writing / May 5, 2026

Hexagonal architecture in production: Share Agent, BIST, and 12 indicators

Share Agent is a stock analysis and automated trading platform for BIST Katılım Endeksi (XKTUM). Python 3.12, FastAPI, hexagonal ports-and-adapters, TimescaleDB, and three paper-trading agents. Notes from building it solo.

Share Agent is an end-to-end stock analysis and automated trading platform for BIST Katılım Endeksi (XKTUM), the Islamic-compliance index of Borsa Istanbul. Three trading agents (short, medium, and long horizon), each capitalized at 100,000 TRY, compute a weighted signal score (-100 to +100) from 12 technical indicators (RSI, MACD, SMA/EMA, Bollinger Bands, Stochastic, VWAP, OBV, ADX, CCI, MFI, ROC, Volume) and fundamental ratios, then execute against the Algolab (Deniz Yatirim) API. The backend is Python 3.12 / FastAPI following a hexagonal ports-and-adapters layout. Agent state is persisted to PostgreSQL (agent_portfolios, agent_positions, agent_trades) so agents survive container restarts. The platform is live at share-agent.rollingcatsoftware.com on a Hetzner CX43 server. The mobile client is Kotlin Multiplatform with Compose (Android ships; iOS is a five-line stub).

The domain core is kept free of framework and IO concerns. The three primary ports are Python ABCs: PriceProvider (OHLCV history and current price), FinancialProvider (fundamentals and balance-sheet items), and ShareRepository (persistence). Adapters that implement those ports include IsYatirimAdapter (primary price data, end-of-day bars), YahooFinanceAdapter (fallback for history plus intraday refresh every five minutes during market hours), KapAdapter (fundamental data from the KAP regulatory platform), AlgolabAdapter (order execution, disarmed by default and requiring two flags to arm for live trading), PostgresShareRepository backed by a TimescaleDB hypertable for price history, and RedisCacheAdapter for symbol-list and computation caches. FallbackPriceProvider implements PriceProvider itself, takes a prioritized list of providers, and tries them in order with bounded timeout and retries per provider. The circuit breaker is a separate pre-trade gate on the live-order path, not part of FallbackPriceProvider. When the primary İs Yatirim feed returned malformed data for two days, I changed one line in the wiring and YahooFinanceAdapter took over; the 12 indicators and signal scorer saw no difference.

XKTUM compliance filtering runs before any signal is acted on. A company must pass: debt ratio below 33%, interest-bearing income below 5% of total revenue, and a buffer-rule flag for companies near those limits. These thresholds come from KAP via KapAdapter. The signal scorer returns a numeric score and a reason vector; classification (BUY/SELL/HOLD and thresholds) is left to each downstream consumer so the domain does not lock in one interpretation.

The scheduler is APScheduler running inside the FastAPI process, with 10 scheduled jobs covering morning signal refresh (10:05), morning trade window (10:15), afternoon refresh (14:15), afternoon trade window (14:30), pre-close snapshot (17:30), evening price ingestion (18:30), evening batch signals (18:45), continuous intraday price refresh every five minutes during market hours, stop-loss monitoring every ten minutes, and a nightly data-quality check. All jobs run weekdays only on Europe/Istanbul time. CI runs ruff (E, F, I, N, W) and pytest on the backend, Gradle for the Android build, and a Docker build-push-deploy workflow on merge.

Repository: github.com/gultekinahmetabdullah/Share-Agent. Live deploy: share-agent.rollingcatsoftware.com.

  • architecture
  • hexagonal
  • trading
  • fastapi