Primus Coinbase $25 MCP Pilot
by Primus19
README.md
# Primus Unified Coinbase Pilot
This MCP server is the authoritative decision and execution ledger for the Coinbase pilot. It does not guarantee profit.
## Solana early-discovery sleeve
`python -m app.solana_early` is a separately deployable discovery service for
new Solana pools and Pump.fun-style launches. It scores contract safety,
sellability, liquidity, unique-buyer acceleration, net buy pressure, holder
distribution, creator behavior, social velocity and the repeatable performance
of participating wallets. A wallet receives predictive credit only after at
least 20 timestamped closed outcomes with positive mean return and a minimum
55% win rate; one lucky trade never creates a "smart wallet" label.
The discovery service never holds a private key or submits swaps. It obtains
new pools and aggregate flow evidence from the keyless GeckoTerminal public API, fails
closed on GoPlus token-control evidence, verifies that a small exit is routable
through Jupiter Swap V2, and accepts authenticated Helius wallet events at
`POST /webhooks/helius`. Deploy with a persistent volume and:
```text
SOLANA_EARLY_ENABLED=true
JUPITER_API_KEY=<secret>
HELIUS_WEBHOOK_AUTH=<random-secret>
SOLANA_WATCH_WALLETS=<comma-separated-public-addresses>
SOLANA_EARLY_LEDGER_PATH=/app/data/solana_early.sqlite3
SOLANA_EARLY_SCAN_INTERVAL_SECONDS=60
SOLANA_EARLY_MIN_SCORE=78
SOLANA_PAPER_MIN_SCORE=25
SOLANA_PAPER_MIN_LIQUIDITY_USD=2500
SOLANA_PAPER_MAX_AGE_MINUTES=1440
SOLANA_PAPER_MIN_BUYERS_5M=3
SOLANA_PAPER_MAX_PRICE_IMPACT_BPS=500
SOLANA_EARLY_MARKET_PAGES=3
SOLANA_EARLY_MAX_CANDIDATES=60
SOLANA_EARLY_MAX_PROBE_USD=3
SOLANA_EARLY_LIVE_ENABLED=false
```
The broader Coinbase research and evidence workers also use CoinGecko's
keyless public market endpoint at bounded intervals. An account key is ignored
unless `COINGECKO_USE_ACCOUNT_KEY=true` is deliberately configured; no paid or
Demo CoinGecko plan is required for the default deployment.
Use `railway.solana-early.json` as the Railway config path. `/health` proves
process and scan health, while `/status` and `/candidates` expose sanitized
paper decisions.
The same discovery process also emits a separate
`SOLANA_PUMPFUN_EV_EXPERIMENT` sleeve. It reuses CoinGecko Onchain, GoPlus,
Jupiter Swap V2, the existing ledger, executor and email path. Because the
shared feed exposes 5-minute aggregates rather than a true 15-second tape, its
probability is explicitly recorded as an uncalibrated proxy and the sleeve is
hard-blocked from live execution. The executor records strategy identity on
every paper position and fill while live execution accepts only
`SOLANA_EARLY_CONTROL` candidates.
```text
SOLANA_PUMPFUN_EV_ENABLED=true
SOLANA_PUMPFUN_EV_TARGET_MCAP_USD=25000
SOLANA_PUMPFUN_EV_MAX_ENTRY_MCAP_USD=15000
SOLANA_PUMPFUN_EV_MIN_TRADES_5M=5
SOLANA_PUMPFUN_EV_MAX_AGE_MINUTES=30
SOLANA_PUMPFUN_EV_ASSUMED_LOSS=0.50
SOLANA_PUMPFUN_EV_MIN_EV_RANK=0.15
```
`services/solana-executor` is a separate signer/executor deployment using
`Dockerfile.solana-executor` and `railway.solana-executor.json`. It consumes
only qualified discovery records, uses Jupiter Swap V2 order/execute, persists
confirmed signatures, reconciles wallet USDC/SOL before entry, limits entries
to $3, total exposure to $6 and two positions, and supervises stop-loss,
take-profit, trailing-stop and 24-hour maximum-hold exits. It remains blocked
until at least 50 paper observations and every live gate are present:
```text
SOLANA_EXECUTOR_ENABLED=true
SOLANA_DISCOVERY_URL=https://<discovery-service>.up.railway.app
SOLANA_EXECUTOR_INTERVAL_SECONDS=60
JUPITER_API_KEY=<secret>
HELIUS_API_KEY=<secret>
SOLANA_WALLET_PRIVATE_KEY=<base58-secret-stored-only-in-Railway>
SOLANA_EXPECTED_WALLET_ADDRESS=<exact-public-mainnet-address>
SOLANA_MIN_PAPER_OBSERVATIONS=50
SOLANA_PAPER_MAX_HOLD_MINUTES=60
SOLANA_PAPER_COST_STRESS_BPS=100
SOLANA_MAX_ENTRY_USD=3
SOLANA_MAX_TOTAL_EXPOSURE_USD=6
SOLANA_MAX_POSITIONS=2
SOLANA_LIVE_ENABLED=false
SOLANA_LIVE_ACK=
```
After forward validation, arm with `SOLANA_LIVE_ENABLED=true` and the exact
acknowledgement `I_ACCEPT_THE_25_USD_SOLANA_EARLY_RISK`. Never paste the wallet
secret into chat, source control, logs, or the discovery service.
Paper exploration deliberately has a broader, separately labeled eligibility
tier so rejected live candidates can generate hypothetical outcomes without
spending funds. Token-control checks, a real Jupiter sell route and the paper
sell-impact ceiling remain mandatory. Paper observations never bypass the live
candidate gates. Live readiness additionally requires positive cost-stressed
paper expectancy after the minimum sample and soak period. The executor also
runs every fully live-qualified candidate through a separate `liveShadow*`
ledger using the exact live sizing, position limit and exit rules. Only that
strict shadow ledger counts toward live promotion; relaxed exploration results
remain visible but can never authorize real execution.
## One report-to-execution chain
1. Market research supplies normalized evidence to `issue_model_3_1_recommendation`.
2. The server calculates the Model 3.1 total from bounded component scores, applies live Coinbase and risk checks, freezes the complete recommendation, and returns a ticket ID plus SHA-256 hash.
3. The hourly report must display that exact stored record.
4. `process_preauthorized_candidate` atomically freezes and processes the same candidate without waiting for an email response. `execute_issued_ticket` remains available for dry-run and diagnostic use.
5. Coinbase product state, cash, live order-book spread, modeled slippage, source age and entry drift are checked again immediately before preview and submission.
6. Entries expire within two minutes. A submitted entry that does not fill within the configured timeout is cancelled instead of being chased. An attached bracket carries the recorded stop and target.
The reporting agent must never invent a live ticket outside this flow.
## Tools
| Tool | Purpose |
|---|---|
| `preflight_coinbase` | Verify portfolio permissions and synchronize capital |
| `list_eligible_spot_products` | Discover current Coinbase USDC spot markets |
| `issue_model_3_1_recommendation` | Score and freeze the exact report/execution record |
| `pilot_status` | Reconcile fills and return the authoritative hourly snapshot, P&L, reviews and notification events |
| `execute_issued_ticket` | Preview or execute only an issued ticket ID/hash |
| `process_preauthorized_candidate` | Atomically freeze, revalidate, preview and process a pre-authorized candidate |
| `emergency_pause` | Block new entries |
| `emergency_flatten` | Cancel the tracked entry and market-sell the tracked asset after explicit confirmation |
| `resume_trading` | Resume only with the required explicit acknowledgement |
## Historical research and backtesting (`app/research`)
Production services only ever see a live snapshot, so until this release no rule in
this repository had a measured historical expectancy; every rule had to earn 100
forward paper closes first. `app/research` is an offline package (optional
dependencies in `requirements-research.txt`, never imported by a deployed service)
that pulls multi-year candles from Coinbase, Kraken, Yahoo and the ECB, and:
- replays the production rules on that history (`replay-crypto` runs the Model 3.1
momentum gate with the research-feed geometry and `lifecycle.supervision_levels`
exits; `replay-forex` rebuilds `market_feed.forex_snapshot` and runs
`ForexEngine`, `trend_continuation_signals` and `bryne_liquidity_signals`);
- backtests candidate per-trade rules with the same risk gates and the production
`promotion_gate`;
- backtests allocation rules (multi-week time-series and cross-sectional momentum).
```bash
python3.12 -m venv .venv && .venv/bin/pip install -r requirements-research.txt
.venv/bin/python -m app.research.cli replay-crypto --fee 120
.venv/bin/python -m app.research.cli replay-forex --spread 1.5
.venv/bin/python -m app.research.cli portfolio --fee 26
```
Findings and the resulting recommendations are in `docs/PROFITABILITY_REVIEW.md`;
raw results are in `docs/research/`. Execution-cost controls added alongside the
research (`LIVE_ENTRY_POST_ONLY`, `LIVE_MAKER_FEE_BPS_PER_SIDE`,
`LIVE_REQUIRE_POSITIVE_1H`, `LIFECYCLE_BREAK_EVEN_INCLUDES_COSTS`) are documented in
`.env.example`.
## Capital and P&L
- The first valid $5-$30 USDC balance is recorded as the initial baseline.
- Later deposits and withdrawals are recorded separately from trading P&L and never expand permitted capital automatically.
- The original baseline plus realized P&L is the only compounding capital. Adding cash to Coinbase does not authorize the executor to use it.
- Realized and unrealized P&L are calculated from Coinbase fills, quantities, prices and commissions—not from balance changes.
- Up to 95% of available permitted capital may be allocated by default, leaving a fee reserve.
- One open position maximum; USDC spot only; no leverage, derivatives, transfers, DEXs, presales or averaging down.
## Circuit breakers
New entries pause automatically after any of:
- two consecutive losing trades;
- 15% daily drawdown;
- 25% drawdown from peak equity.
`emergency_pause` blocks new entries. `emergency_flatten` is a separate destructive action because it can realize a loss. Resuming requires the exact acknowledgement `I_REVIEWED_THE_LOSSES_AND_ACCEPT_RESUMING`.
## Guarded model review
Every hourly `pilot_status` snapshot creates at most one review record for that UTC hour. Every closed trade creates a trade-specific review. Reviews track sample size, wins/losses, win rate, net expectancy and profit factor.
The champion remains locked until at least 100 closed outcomes exist. Promotion also requires a positive 95% lower confidence bound, positive cost-stressed expectancy, and prospective challenger performance without worse drawdown. The server does not rewrite weights after a handful of wins or losses and never loosens safety controls automatically.
## Email reporting without SMTP
No SMTP server or app password is required. `pilot_status` returns an append-only notification/event feed plus the exact recommendations and review results. The existing ChatGPT scheduled task uses its connected Gmail account to format and email that snapshot.
This produces hourly reporting. Immediate server-originated email would require a separate mail provider, which is intentionally not required here.
## Security and deployment
- `/mcp` uses GitHub OAuth.
- `/api/pilot-status` requires `Authorization: Bearer $REST_API_TOKEN`.
- Coinbase credentials are entered only through `/setup?token=...`, encrypted at rest, and never returned through MCP.
- The Coinbase key must be portfolio-scoped with View + Trade and Transfer disabled.
- Rotate `SETUP_TOKEN` after setup.
- Keep a persistent Railway volume mounted at `/app/data`.
Required variables are documented in `.env.example`.
### OAuth deployment checklist
Use these exact values for the deployed Railway service:
```text
PUBLIC_BASE_URL=https://memecoin-mcp-server-production.up.railway.app
```
Do not append `/mcp` to `PUBLIC_BASE_URL`. In the GitHub OAuth App, set the authorization callback URL exactly to:
```text
https://memecoin-mcp-server-production.up.railway.app/auth/callback
```
Set `JWT_SIGNING_KEY` in Railway to a stable, randomly generated secret of at least 32 bytes. Do not paste that secret into ChatGPT, commit it, or rotate it casually: FastMCP uses it to sign OAuth proxy tokens. Keep the Railway volume mounted at `/app/data` so dynamically registered ChatGPT clients survive deploys and restarts.
After deployment, `/health` reports only non-secret OAuth diagnostics: the canonical base URL, exact callback URL, FastMCP version, signing-key presence, and whether persistent client storage is under `/app/data`.
Keep live execution locked while refreshing and testing the new MCP schema:
```text
LIVE_TRADING=false
LIVE_CONFIRMATION=
```
Arm only after preflight, product discovery, recommendation issuance, dry-run ticket execution, fill reconciliation, circuit-breaker and Gmail-report tests pass:
```text
LIVE_TRADING=true
LIVE_CONFIRMATION=I_ACCEPT_THE_25_USDC_LIVE_RISK
```
For unattended operation, a trusted signal worker may call `POST /api/auto-candidate` with `Authorization: Bearer $REST_API_TOKEN`. That endpoint invokes the exact same freeze, risk, preview and execution code as the MCP tool. Keep the bearer token only in the worker's secret manager. MCP write actions may still require ChatGPT confirmation and are not the low-latency path.
## Pre-authorized fast path
The fast path is disabled unless both live environment variables are armed. It does not weaken the Model 3.1 gates. Each candidate must be based on market data no more than two minutes old, and execution independently requires a live spread and modeled slippage of at most 50 bps, entry drift of at most 35 bps, a best ask at or below the frozen entry ceiling, one-position maximum, and the existing $2.50 loss cap. The order is previewed before submission and carries an attached stop/target bracket.
Some ChatGPT clients cache an older MCP tool list. Set `PREAUTHORIZED_AUTO_EXECUTION=true` to make the existing `issue_model_3_1_recommendation` tool invoke the exact same atomic fast path as `process_preauthorized_candidate`. This compatibility mode does not bypass any validation. With `LIVE_TRADING=false`, it performs a dry run only. `/health` reports schema version 3.3, the frozen opportunity-policy defaults, and whether compatibility mode is enabled without exposing secrets.
The caller no longer supplies authoritative Coinbase execution facts. Before a
candidate is accepted, the server fetches the Coinbase product and order book
and overwrites `identity_verified`, `spot_available`, `spread_bps` and
`slippage_bps`. The frozen ticket includes timestamped `coinbase_evidence`.
Research still must supply fresh, auditable regime, momentum, market-cap,
volume, news, social, tokenomics and safety evidence; missing research evidence
is never converted into a passing score.
## Opportunity policy 1.0
Model 3.1 component weights remain unchanged. A separately versioned,
human-directed opportunity policy controls whether a clean research candidate
may advance to the executor. The exact policy is frozen into every ticket and
therefore covered by the recommendation hash.
The default policy now:
- permits a strong candidate in a MIXED regime while continuing to reject a
FALLING regime;
- uses a 78-point minimum;
- awards zero news points when no catalyst is verified instead of suppressing
an otherwise clean established asset;
- keeps any verified negative-news veto hard;
- uses $25M market cap, $5M volume and 3%-150% turnover opportunity floors;
- keeps the 15% daily momentum chase ceiling.
This does **not** relax exact identity, clean contract safety, Coinbase spot
availability, USDC-only execution, live spread/slippage, source freshness,
entry drift, one-position maximum, capital limits, the $2.50 loss cap, attached
exit protection, or circuit breakers. Set `LIVE_REQUIRE_NEWS_CATALYST=true` to
restore the event-driven catalyst requirement without changing code.
## Two consolidated paper services
Production exposes exactly two logical paper portfolios:
- `UNIFIED_FOREX_PAPER_V1` owns the active Bryne and Lot-Bill V5 paper lifecycle.
Earlier V2/V3/V4 variants remain read-only historical component evidence and
cannot generate entries.
- `UNIFIED_CRYPTO_PAPER_V1` combines Solana Early, Divine, Microcap, the
executable sub-$1M shadow cohort, and Runner Capture under one paper ledger,
one position owner, and one aggregate performance/promotion gate.
Component strategy identifiers are deliberately retained on every observation
and fill. They are attribution labels, not separately deployed paper services.
The Coinbase, Solana and Forex live executors remain independent and unchanged;
paper evidence can never promote or alter live risk automatically.
## Legacy paper-only multi-asset engines
`python -m app.asset_worker` consumes normalized, source-linked snapshots and
runs independent paper sleeves, including:
- `FOREX_TREND`: aligned 1h/24h trend, liquid session, spread and economic-event
distance checks;
- `EQUITY_MOMENTUM`: positive 1h/24h momentum, relative volume, VWAP, halt and
broad-market checks;
- defined-risk options: call-debit and put-debit spreads only, with verified
legs, minimum open interest, IV context, expiry and whole-contract sizing
from the verified maximum loss per complete spread (including multiplier and
estimated fees).
- `MULTI_WEEK_CRYPTO_MOMENTUM_V1`: chain-neutral 3–12 week trend research.
The multi-asset feed attempts public Coinbase spot order books before its CoinGecko
fallback. Coinbase candidates use executable ask/bid depth and a configurable,
fee-stressed round-trip probe. They do not claim unavailable on-chain holder or
creator evidence. CoinGecko-only candidates remain forward-tracking controls until
an execution and contract-safety adapter supplies the missing facts.
The same consolidated paper sleeve also discovers emerging Base, Solana and
Robinhood-chain tokens dynamically from DEX Screener profiles and boosts. It
retrieves daily pool candles from GeckoTerminal, applies a fee- and AMM-impact
stressed round trip, and requests GoPlus contract and concentration evidence for
Base and Solana. Unsupported-chain assets remain visible forward-tracking controls
and cannot enter, rather than receiving invented safety approval. DEX execution is
modeled for research only and cannot authorize a live order. Emerging research
holds also require two independent observations at least 12 hours apart. A coin
that falls more than 5%, draws down more than 20%, or rises more than 50% during
that confirmation window remains tracked but does not consume paper budget.
It requires verified full-size sellability, contract/distribution evidence,
two confirmations at least 12 hours apart, daily higher highs and lows,
positive weekly relative strength, persistent volume, holder growth, and a
controlled pullback or consolidation. It opens only a 25% paper stage,
records partial profit at 2R, protects larger favorable excursions, and exits
on multi-factor trend or execution deterioration. Candidate discovery is
universe-driven; example contracts are never treated as a fixed watchlist.
The worker writes an append-only JSONL ledger. It has no broker adapter and
cannot submit a live forex, equity or option order in this release. This is
intentional: each sleeve must first collect forward paper results and later use
a broker-specific preflight, preview, idempotency and reconciliation adapter.
Enable paper sleeves independently:
```text
MULTI_ASSET_WORKER_ENABLED=true
MULTI_ASSET_FEED_URL=https://your-normalized-feed.example/snapshots
FOREX_ENGINE_ENABLED=true
EQUITY_ENGINE_ENABLED=true
OPTION_ENGINE_ENABLED=true
CRYPTO_ENGINE_ENABLED=true
MULTI_ASSET_LEDGER_PATH=/app/data/multi_asset.jsonl
ASSET_MAX_OPEN_POSITIONS=3
ASSET_MAX_HOLD_MINUTES=240
```
The feed returns `{"snapshots": [...]}`. Every snapshot must contain a fresh
`observed_at`, at least one HTTPS source, `tradable=true`, a reference price,
spread, stop distance, maximum loss, thesis and invalidation. Asset-specific
fields are validated before a proposal can become a paper fill.
### Deployable multi-asset services
The broker-backed paper release adds three independently deployable processes:
- `python -m app.market_feed` obtains OANDA pricing and candles and emits
normalized Forex snapshots;
- `python -m app.asset_worker` creates append-only paper proposals and fills;
- `python -m app.asset_supervisor` marks paper positions and appends stop/target
closes without rewriting history.
`app.broker_adapters` provides read-only preflight and order-preview structures
for OANDA and Alpaca. No method in this release submits a Forex, equity, or
option order. `MULTI_ASSET_LIVE_ENABLED` defaults to false. A separately
reviewed execution adapter must add idempotent submission, reconciliation,
attached protection, and emergency exits before live use.
The paper worker exposes `/report.json` and `/status`; set
`MULTI_ASSET_REPORT_TOKEN` to require a bearer token on both routes while
leaving `/health` available to Railway. Multi-week crypto entries, staged
adds, partial profits and exits generate immediate paper-trade email alerts.
An additional current-state summary is sent every four hours, including the
universe/feed state, open positions, MFE/MAE and realized P&L. Delivery is
restart-safe and its status/error is published as `email_delivery`.
The central trading dashboard reads this report through
`DASHBOARD_MULTI_ASSET_URLS` and displays the multi-week ledger as a first-class
paper portfolio: invested/current USD, unrealized USD and percentage P&L,
MFE/MAE, monitoring freshness, stop state and recent actions. Multi-week risk
decisions use current executable marks. Hard exits and initial stops take
precedence over partial-profit tiers; an uncaptured historical peak is recorded
as missed profit and can never be presented as an executable profit fill.
Required Forex feed variables:
```text
MULTI_ASSET_FEED_ENABLED=true
OANDA_ENVIRONMENT=practice
OANDA_API_TOKEN=<Railway secret>
OANDA_ACCOUNT_ID=<Railway secret>
FOREX_SYMBOLS=EUR_USD,GBP_USD,USD_JPY,AUD_USD,USD_CAD,USD_CHF,NZD_USD,EUR_JPY,GBP_JPY,EUR_GBP
FOREX_DEFAULT_EVENT_DISTANCE_MINUTES=0
MULTI_ASSET_FEED_INTERVAL_SECONDS=60
```
`FOREX_DEFAULT_EVENT_DISTANCE_MINUTES=0` intentionally vetoes entries until a
trusted economic-calendar adapter attests that the event window is clear.
The paper worker is the sole ledger writer and position owner. The supervisor
reads the worker's private `/report.json`; it must not mount or mutate a second
copy of `multi_asset.jsonl`.
## Authoritative Forex executor
`python -m app.forex_executor` is the hardened single-writer Forex lifecycle
service. It stores intents, broker identifiers and a hash-chained audit stream
in SQLite on a Railway volume, independently rechecks OANDA pricing and
home-currency risk, suppresses duplicate intents, attaches stop-loss and
take-profit protection to an accepted OANDA order, and reconciles broker state.
It is paper-only unless **all** independent live gates are present. Never reuse
the practice deployment or database for a production account.
```text
FOREX_EXECUTOR_ENABLED=true
FOREX_EXECUTOR_INTERVAL_SECONDS=30
FOREX_LEDGER_PATH=/app/data/forex.sqlite3
MULTI_ASSET_FEED_URL=https://multi-asset-market-feed-production.up.railway.app/snapshots
FOREX_MIN_SCORE=80
FOREX_MAX_RISK_USD=0.50
FOREX_MAX_OPEN_POSITIONS=1
FOREX_MAX_COMBINED_RISK_USD=0.50
FOREX_DAILY_LOSS_LIMIT_USD=2.50
FOREX_MAX_NOTIONAL_USD=50.00
FOREX_MAX_MARGIN_USED_USD=5.00
FOREX_MAX_ENTRY_DRIFT_BPS=15
```
The approved production limit is hard-coded at one position with $0.50 maximum
planned loss and cannot be raised by stale Railway variables. Two protected
positions created during the briefly expanded policy are reconciled and
supervised to their normal exits, but no additional entry is admitted.
Use `/railway.forex-executor.json` as the custom Railway config path for both
Forex executor services. `/health` is process liveness and remains HTTP 200
while the server is running; `executor_ready` reports dependency readiness.
`/status` remains fail-closed with HTTP 503 until broker reconciliation and the
market-feed scan succeed. The executor can authenticate to the market feed with
the optional `MULTI_ASSET_FEED_BEARER_TOKEN` secret.
The executor also publishes `/report` as an email-client-safe HTML Forex
dashboard and `/report.json` as the exact machine-readable report snapshot.
## Cross-strategy intelligence ledger
The unified dashboard continuously consolidates Forex Control, every Bryne and
Lot-Bill version, Coinbase meme trading, Solana Early, Divine, Microcap and
Runner evidence into `/app/data/trading_intelligence.sqlite3`. The append-only
ledger preserves the source payload and provenance hash, normalized trades and
decisions, failed-rule severity, fees, MFE/MAE, and executable 5/15/30/60/120/240
minute checkpoints. It separates production-qualified, paper-qualified,
near-miss shadow, research shadow and hard-rejection control cohorts so inactive
strategies can be evaluated without weakening immutable safety or sellability
rules.
Authenticated users can inspect the Intelligence Ledger dashboard tab or
`/intelligence.json`. Learnings are saved with their evidence IDs, sample size,
cost-stressed expectancy and adoption threshold. The ledger never changes live
risk or promotes a strategy automatically: exit mechanisms require 30–50
independent closes, while entry-model or risk promotion requires at least 100
independent cost-stressed trades with positive expectancy.
For reliable production delivery, the executor can send the generated HTML
itself instead of relying on a connected-chat Gmail action. Delivery is opt-in,
uses the existing SQLite ledger to suppress duplicates across restarts, retries
transient failures without changing executor readiness, and records only
sanitized delivery events. Configure the live Forex Railway service with:
```text
FOREX_EMAIL_REPORT_ENABLED=true
FOREX_EMAIL_PROVIDER=gmail_api
FOREX_EMAIL_TIMEZONE=America/New_York
FOREX_EMAIL_RECIPIENTS=first@example.com,second@example.com
FOREX_EMAIL_FROM=your-account@gmail.com
FOREX_EMAIL_GMAIL_CLIENT_ID=<Railway secret>
FOREX_EMAIL_GMAIL_CLIENT_SECRET=<Railway secret>
FOREX_EMAIL_GMAIL_REFRESH_TOKEN=<Railway secret>
FOREX_EMAIL_TIMEOUT_SECONDS=20
FOREX_EMAIL_RETRY_SECONDS=300
```
`gmail_api` sends from an existing Gmail account over HTTPS port 443 and does not require a custom domain. Enable the Gmail API, grant only the `gmail.send` OAuth scope, and store the OAuth client ID, client secret and refresh token in Railway secrets. `resend` and `smtp` remain optional fallback providers.
The subject is `[HOURLY] Forex Live Trading Dashboard - YYYY-MM-DD HH:00 ET`.
A successful send stores the ET hour in the ledger, so restarts and repeated
30-second scans cannot create duplicate messages. SMTP errors are exposed in
`email_delivery` and the audit stream, but they never authorize trades or make
the executor unready. Keep credentials only in Railway secrets. Once this path
is verified, disable the old connected-Gmail Forex task to avoid duplicates.
`FOREX_MIN_SCORE` is independent from the generic multi-asset score setting so
a sentinel used by another sleeve cannot silently disable Forex. Every closed
trade is reviewed net of financing, with win rate, expectancy, profit factor,
maximum favorable/adverse excursion, profit capture and symbol breakdowns.
The champion remains locked for at least 100 closed trades. Any later change
must be evaluated as a prospective challenger and cannot loosen risk controls.
## Emerging meme-coin tier
The established meme-coin tier remains unchanged at a minimum $25 million
market cap, $5 million 24-hour volume and model score 78. An additional
emerging tier can consider lower-volume markets without giving them the same
capital allocation:
```text
LIVE_EMERGING_MEME_ENABLED=true
LIVE_EMERGING_MIN_SCORE=84
LIVE_EMERGING_MIN_MARKET_CAP_USD=10000000
LIVE_EMERGING_MIN_VOLUME_24H_USD=1000000
LIVE_EMERGING_MAX_SPREAD_BPS=30
LIVE_EMERGING_MAX_SLIPPAGE_BPS=30
LIVE_ESTIMATED_FEE_BPS_PER_SIDE=120
LIVE_MIN_NET_EDGE_BPS=50
PILOT_EMERGING_NOTIONAL_USDC=5.00
PILOT_EMERGING_MAX_LOSS_USDC=0.25
```
Emerging candidates must still pass identity, safety, catalyst, turnover,
momentum, regime and execution-quality gates. Their order size is fixed at $5,
planned loss is capped at $0.25 and the model threshold is higher than the
established tier. Rejected candidates are retained as shadow observations so
future threshold changes can be evaluated against outcomes rather than trade
frequency alone.
Live mode additionally requires all four values below plus a current verified
economic-calendar response. Missing or inconsistent values fail closed:
```text
OANDA_ENVIRONMENT=live
FOREX_LIVE_ENABLED=true
FOREX_LIVE_ACK=I_ACCEPT_REAL_MONEY_RISK
FOREX_ALLOWED_ACCOUNT_ID=<exact live v20 account id>
FOREX_LIVE_BASELINE_USD=<broker-confirmed starting balance>
```
The market feed accepts a normalized calendar endpoint through
`ECONOMIC_CALENDAR_URL` and optional `ECONOMIC_CALENDAR_BEARER_TOKEN`. Its
response must contain a fresh `observed_at`, direct HTTPS `source_url`, and
currency-tagged high-impact events. The fixed
`FOREX_DEFAULT_EVENT_DISTANCE_MINUTES` value is never accepted as verified
calendar evidence for live orders.
Before live promotion, exercise the identical broker path against OANDA
practice with virtual funds:
```text
OANDA_ENVIRONMENT=practice
FOREX_PRACTICE_EXECUTION_ENABLED=true
FOREX_PRACTICE_ACK=I_ACCEPT_PRACTICE_ORDER_EXECUTION
```
Run `python -m app.economic_calendar` as a separate service to normalize a
trusted upstream calendar into the `/events` schema consumed by the market
feed. Configure `ECONOMIC_CALENDAR_UPSTREAM_URL`, optional
`ECONOMIC_CALENDAR_UPSTREAM_TOKEN`, and point the market feed's
`ECONOMIC_CALENDAR_URL` to this service's `/events` endpoint.
For the Railway service named `forex-economic-calendar`, set its config file
path to `/railway.economic-calendar.json`. The repository then owns the custom
start command, `/health` healthcheck, 120-second timeout, dedicated Dockerfile,
and exposed port 8080. The process binds to `0.0.0.0` and reads Railway's
`PORT` variable, defaulting to 8080 for local runs.
The recommended no-subscription mode is the fail-closed official composite. It
fetches FRED Employment Situation, CPI and PPI calendars plus Federal Reserve,
ECB, Bank of England and Bank of Japan policy schedules, normalizes local
release times to UTC, and attests coverage separately from the event list. A
quiet lookahead window is therefore valid only when all required currency
sources were successfully fetched. BOJ decisions use an extended
event-specific blackout because their exact release time is not promised.
Railway may throttle or time out some official calendar sites. The scheduled
`refresh-official-calendar.yml` workflow therefore validates the same sources
from GitHub every 12 hours and commits a 31-day normalized snapshot. Railway
uses that snapshot only when the direct refresh fails, only while it is less
than 36 hours old, and only when all required currency coverage and HTTPS
source checks pass. A stale or incomplete snapshot still fails closed:
```text
ECONOMIC_CALENDAR_ENABLED=true
ECONOMIC_CALENDAR_PROVIDER=official_composite
OFFICIAL_CALENDAR_REQUIRED_CURRENCIES=USD,EUR,GBP,JPY
ECONOMIC_CALENDAR_LOOKAHEAD_DAYS=7
ECONOMIC_CALENDAR_INTERVAL_SECONDS=300
OFFICIAL_CALENDAR_SNAPSHOT_MAX_AGE_SECONDS=129600
```
No API key is required. `/health` is a process-liveness endpoint and always
returns HTTP 200 while the server is running; its `calendar_ready` field shows
whether verified calendar data is available. If any required official source
is unreachable or its format is no longer recognized, `/events` returns HTTP
503 rather than silently treating the week as event-free.
The first-class Trading Economics adapter remains available as an optional
paid fallback. It requests high-importance events for a bounded set of
major-currency countries, maps country names to ISO currency codes, normalizes
timestamps to UTC, rejects empty/unrecognized responses, and never publishes
its API key:
```text
ECONOMIC_CALENDAR_ENABLED=true
ECONOMIC_CALENDAR_PROVIDER=trading_economics
TRADING_ECONOMICS_API_KEY=<Railway secret from developer.tradingeconomics.com>
TRADING_ECONOMICS_COUNTRIES=united states,euro area,united kingdom,japan,canada,australia
ECONOMIC_CALENDAR_LOOKAHEAD_DAYS=7
ECONOMIC_CALENDAR_REQUIRE_EVENTS=true
ECONOMIC_CALENDAR_INTERVAL_SECONDS=300
```
The generic HTTPS JSON mode remains available. Query strings are stripped from
the public `source_url` so credentials cannot leak into feed evidence.
## Continuous signal worker
Run `python -m app.signal_worker` as a separate Railway service. It polls a
trusted research feed every 5-60 seconds (15 seconds by default), discards data
older than the configured freshness window, deduplicates candidates, and sends
only fresh complete payloads to the authenticated `/api/auto-candidate` route.
It never creates scores, fills missing news/safety evidence, or holds Coinbase
credentials. The executor performs the final Coinbase and portfolio checks.
Required worker variables:
```text
SIGNAL_WORKER_ENABLED=true
SIGNAL_SCAN_INTERVAL_SECONDS=15
SIGNAL_MAX_AGE_SECONDS=90
SIGNAL_FEED_URL=https://your-trusted-research-feed.example/candidates
SIGNAL_FEED_BEARER_TOKEN=<feed-specific secret, if required>
EXECUTOR_BASE_URL=https://memecoin-mcp-server-production.up.railway.app
REST_API_TOKEN=<same executor bearer token>
```
Keep `LIVE_TRADING=false` on the executor while testing. A healthy worker writes
`/app/data/signal_worker_status.json` and emits structured `SIGNAL_SCAN` logs.
Once a dry-run candidate returns `DRY_RUN_ONLY`, live mode can be armed on the
executor without changing the worker. The worker is a low-latency transport,
not a substitute for a genuine always-on research feed. If the feed is missing,
stale, malformed, or unavailable, it fails closed and forwards nothing.
## Continuous position supervisor
Run `python -m app.position_worker` as a separate Railway background service.
It polls the authoritative executor every 5-60 seconds, reconciles Coinbase
fills, records the +15% milestone, ratchets an 8% trailing exit after +12%, and
submits a managed exit on a FALLING regime. The Coinbase-attached hard stop and
+30% target remain live at the venue if the supervisor or Railway is offline.
Before a managed exit, the executor cancels open sell orders and uses only the
then-available base balance, preventing an intentional oversell.
Required supervisor variables:
```text
POSITION_SUPERVISOR_ENABLED=true
POSITION_SUPERVISION_INTERVAL_SECONDS=15
EXECUTOR_BASE_URL=https://memecoin-mcp-server-production.up.railway.app
REST_API_TOKEN=<same executor bearer token>
RESEARCH_FEED_URL=https://memecoin-research-feed-production.up.railway.app
SIGNAL_FEED_BEARER_TOKEN=<same research-feed bearer token>
```
Use start command `python -m app.position_worker`. It exposes `/health` for
Railway but does not need a public domain. Every entry fill, target milestone,
managed exit, close, error, pause and model review is written to the executor's
append-only event feed returned by `pilot_status`. The connected ChatGPT Gmail
task must use `pilot_status` as the live-pilot source of truth in every report.
## Continuous research-feed producer
Run `python -m app.research_feed` as a third Railway service from this same
repository. It continuously scans the broad CoinGecko market universe, using
at least four pages or 1,000 assets and up to 2,500 when configured, then
intersects unique symbols with the executor's actual eligible Coinbase USDC
products, classifies liquid breadth, calculates the bounded Model 3.1
components, and publishes fresh candidates at `GET /candidates`.
The feed deliberately separates automatically observed market facts from
verified qualitative evidence. A candidate is not published until an
authenticated evidence adapter has submitted fresh identity, safety and news
attestations to `POST /evidence`. Missing evidence is zero—not neutral—and the
scanner fails closed. This prevents an article snippet, duplicate symbol, or
unsupported safety claim from becoming a real order.
Research-feed variables:
```text
RESEARCH_FEED_ENABLED=true
RESEARCH_SCAN_INTERVAL_SECONDS=30
RESEARCH_MARKET_PAGES=4
RESEARCH_HTTP_MAX_RETRIES=3
RESEARCH_HTTP_RETRY_BACKOFF_SECONDS=1
RESEARCH_REQUEST_SPACING_SECONDS=1
EXECUTOR_BASE_URL=https://memecoin-mcp-server-production.up.railway.app
REST_API_TOKEN=<same executor bearer token>
SIGNAL_FEED_BEARER_TOKEN=<new independent random bearer token>
COINGECKO_API_KEY=<optional CoinGecko demo/pro key>
RESEARCH_FEED_STATE_PATH=/app/data/research_feed.json
PORT=8080
```
Give the research service a Railway volume at `/app/data` and set its start
command to `python -m app.research_feed`. Railway creates its public domain; the
worker's `SIGNAL_FEED_URL` is that domain plus `/candidates`, and the worker's
`SIGNAL_FEED_BEARER_TOKEN` must equal the research service's token.
Generate that shared token yourself in a password manager or with
`python -c "import secrets; print(secrets.token_urlsafe(48))"`; the service does
not print or expose secrets. `/health` is public and contains no evidence or
candidate payloads. `/candidates`, `/status`, and `/evidence` require the bearer
token.
Evidence submissions must include `coin_id`, `product_id`, `identity_verified`,
`no_safety_veto`, bounded `safety_score`, `news_score` and `social_score`, HTTPS
`source_urls`, `observed_at`, `expires_at`, `thesis`, and `invalidation`. This
endpoint is intended for a separately reviewed news/safety adapter; it is not a
way to assert passing values without source-backed verification.
End-to-end Railway topology:
1. Research service publishes authenticated `/candidates`.
2. Worker polls it and forwards each stable `signal_id` once.
3. Executor independently rechecks Coinbase identity, order book, capital,
one-position limit, spread, slippage, drift, stop and loss cap.
4. Any missing/stale/conflicting fact stops the chain.
## Continuous evidence adapter
Run `python -m app.evidence_worker` as a fourth Railway service. It intersects
unique symbols from the broad crypto market with eligible Coinbase USDC products, verifies
CoinGecko asset identity, requires complete clean GoPlus token-security
facts, and requires positive catalyst coverage from at least two independent
configured RSS domains. A two-source exploit, hack, rug, honeypot, delisting,
compromise, breach or chain-halt report is a veto. Missing contract fields,
unsupported chains, ambiguous symbols, missing holder data and single-source
news all fail closed. Social receives zero because the adapter has no reliable
public account-quality and bot-analysis source.
Native assets with no token contract are recognized explicitly, so contract-only
checks such as mint authority and honeypot status are treated as not applicable.
Tokens that advertise a platform but lack one canonical contract still fail closed.
Required variables:
```text
EVIDENCE_ADAPTER_ENABLED=true
EVIDENCE_SCAN_INTERVAL_SECONDS=300
EVIDENCE_MARKET_PAGES=4
EVIDENCE_REQUEST_SPACING_SECONDS=2.5
EVIDENCE_HTTP_MAX_RETRIES=3
EXECUTOR_BASE_URL=https://memecoin-mcp-server-production.up.railway.app
REST_API_TOKEN=<reference the executor token>
RESEARCH_FEED_URL=https://memecoin-research-feed-production.up.railway.app
SIGNAL_FEED_BEARER_TOKEN=<reference the research-feed token>
COINGECKO_API_KEY=<optional demo/pro key>
EVIDENCE_NEWS_RSS_URLS=<optional comma-separated reviewed RSS URLs>
```
The adapter has no Coinbase credentials and cannot place orders. It only posts
bounded evidence to the authenticated research service. Keep
`LIVE_TRADING=false` until a genuine adapter-produced candidate completes the
full path and returns `DRY_RUN_ONLY`. Do not use fabricated evidence to force a
production test.
The evidence adapter uses the same established and emerging liquidity policy
as the research feed. Candidates are ranked with an auditable top-ten summary
using model score, safety, verified news, and 1-hour momentum. Product identity
does not impose a cooldown or preference: the top-ranked qualifying candidate
advances, while every safety and execution gate remains authoritative.
The adapter spaces requests per upstream host, honors HTTP `Retry-After`, uses
bounded retries, caches CoinGecko identity metadata for six hours, and isolates
per-token source failures. A rate-limited token is rejected for that cycle; it
is never filled with stale or invented evidence and does not abort the rest of
the scan.
## Tests
```bash
python -m py_compile app/*.py tests/*.py
PYTHONPATH=. python -m unittest discover -s tests -v
```
References: [OpenAI MCP documentation](https://developers.openai.com/api/docs/mcp), [Coinbase Advanced Trade endpoints](https://docs.cdp.coinbase.com/coinbase-app/advanced-trade-apis/rest-api), and [Coinbase Products API](https://docs.cdp.coinbase.com/api-reference/advanced-trade-api/rest-api/products/list-products).
Microcap also retains a strictly shadow-only `$100k-$1m` executable cohort. It never
sets `paper_qualified` or `live_eligible`; candidates must pass verified contract safety,
the configured volume and liquidity floors, holder concentration, and a full-size
Jupiter sell simulation within the existing impact limit. Executable outcomes are
stored at 5/15/30/60/120/240 minutes for later cost-stressed evaluation. Live gates
remain unchanged, and promotion still requires 100 independent positive-expectancy
cost-stressed observations.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues