fix: marketable entries price from live last + time-of-day rvol arms fast path

Day-22 forensic (BIYA session): 6 entry submissions, 0 fills — IREX missed
+1.7R, IRE +1.65R by one cent. Two root causes fixed:

1. Slow-path limit rested AT the trigger while price ran 2% past it, and
   retries reused the same stale price. Marketable model now prices from
   max(trigger, live last) via price_provider; the anti-chase extension
   gate gets the live ref too (was an entry_ref==trigger no-op on this
   path). TRADING_ENTRY_FILL_MODEL flipped to marketable.

2. Fast trigger path armed nothing all day: legacy rvol (cum-so-far /
   full-day MEAN) is ~0.1-0.3 minutes after the open for a normal heavy
   name and its mean is poisoned by reverse-split/prior-squeeze days
   (BIYA legacy 1.27 vs real activity 481x median). New rvol_tod =
   cum / (MEDIAN(20d) * elapsed-session fraction) drives arm eligibility
   and the scanner keep-filter; legacy rvol untouched for validated
   boundaries (gap-squeeze rvol>=5).

Also: stagnation time-stop (TRADING_EXIT_STAGNATION_MIN/_R, default OFF)
in simulate_exit + manage_live with sweep_exits.py variants for
validation before any live enable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
momentum devandClaude Fable 5 committed 2026-07-20 15:40:15 -05:00
1 parent f10a8033a1
commit 5597250ff1
11 files changed
+894 -8

No files matched your search

+687
View File
@@ -0,0 +1,687 @@
# TrueNAS SCALE custom-app compose - FLATTENED (no YAML anchors).
# TrueNAS's app validator REJECTS anchors (x-app / <<: *app) with
# 'Invalid YAML provided', so every service carries its own full env.
# Anchored/DRY source of truth: deploy/docker/truenas-compose.yml.
# Fill every <FILL-ME-*> before deploying (PG password repeats in all
# DATABASE_URL blocks + postgres + db-backup). Regenerated? keep both in sync.
#
services:
postgres:
image: postgres:18
environment:
POSTGRES_USER: momentum
POSTGRES_PASSWORD: <FILL-ME-PG-PASSWORD>
POSTGRES_DB: momentum
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- /mnt/volume/Apps/momentum/pgdata:/var/lib/postgresql/data
ports:
- 5433:5432
healthcheck:
test:
- CMD-SHELL
- pg_isready -U momentum -d momentum
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
loop:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- run_live_paper.py
- --no-dashboard
environment:
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets/v2
ALPACA_DATA_FEED: sip
ALPACA_PAPER_SYNC_ENABLED: '1'
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
DEADMAN_DAILY_PING: '1'
DEADMAN_STALE_MIN: '5'
DISCOVER_INTERVAL_SECONDS: '120'
FMP_API_KEY: <FILL-ME-FMP-KEY>
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
LIVE_BARS_INTERVAL_SECONDS: '20'
LIVE_BARS_REFRESH_MINUTES: '20'
NEWS_CATALYST_SCORE_ENABLED: '1'
NEWS_DILUTION_VETO_ENABLED: '1'
NEWS_ENRICH_BATCH_LIMIT: '50'
NEWS_ENRICH_ENABLED: '1'
NEWS_ENRICH_INTERVAL_SECONDS: '120'
NEWS_ENRICH_LOOKBACK_HOURS: '12'
NEWS_FEEDS: prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
NEWS_LOOKBACK_HOURS: '8'
NEWS_RANK_BOOST: '2.0'
OLLAMA_ENABLED: '1'
OLLAMA_HOST: http://192.168.1.5:30068
OLLAMA_MODEL: qwen2.5:7b-instruct
OLLAMA_TEMPERATURE: '0.1'
OLLAMA_TIMEOUT_SECONDS: '60'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '1'
STRATEGY_SETUPS: opening_range_break
TELEGRAM_BOT_TOKEN: <FILL-ME-TELEGRAM-TOKEN>
TELEGRAM_CHAT_ID: <FILL-ME-TELEGRAM-CHAT-ID>
TRADING_AUTO_APPROVE: '1'
TRADING_BACKOUT_COOLDOWN_SECONDS: '180'
TRADING_BLOCK_REENTRY_AFTER_EXIT: '1'
TRADING_ENTRY_CONFIRM_BY_MINUTE: '0'
TRADING_ENTRY_FILL_MODEL: marketable
TRADING_ENTRY_INVALIDATE_PCT: '0.015'
TRADING_ENTRY_ORDER_TYPE: limit
TRADING_ENTRY_TIMEOUT_BARS: '2'
TRADING_EOD_FLATTEN_ENABLED: '1'
TRADING_EOD_FLATTEN_TIME: '15:55'
TRADING_EXECUTION_ENABLED: '1'
TRADING_EXIT_BREAKEVEN_R: '1.0'
TRADING_EXIT_PROFIT_TIERS: 8:3,15:9,25:18,40:30
TRADING_EXIT_TRAIL_AFTER_R: '1.0'
TRADING_EXIT_TRAIL_MODE: prior_low
TRADING_EXIT_TRAIL_R_STEP: '0.25'
TRADING_LIQUIDITY_MAX_VOLUME_PCT: '0.025'
TRADING_MAX_BACKOUTS_PER_SYMBOL: '3'
TRADING_MAX_CONCURRENT_POSITIONS: '10'
TRADING_MAX_DAILY_LOSS_PCT: '0.05'
TRADING_MAX_FRESH_ENTRIES_PER_DAY: '10'
TRADING_MAX_GROSS_NOTIONAL_PCT: '0.60'
TRADING_MAX_ORDERS_PER_TICK: '1'
TRADING_MAX_POSITION_PCT: '0.16'
TRADING_MAX_RISK_DOLLARS: '500'
TRADING_MIN_DAY_VOLUME: '300000'
TRADING_MIN_ENTRY_GAP_PCT: '0.10'
TRADING_MIN_QUALITY_SCORE: '0.60'
TRADING_PRICE_MAX: '20.0'
TRADING_PRICE_MIN: '2.0'
TRADING_REENTRY_MIN_LOSS_PCT: '0.01'
TRADING_REGIME_GATE_ENABLED: '1'
TRADING_REGIME_GATE_P_MIN: '0.5'
TRADING_REQUIRE_ABOVE_VWAP: '1'
TRADING_REWARD_MULTIPLE: '10.0'
TRADING_RISK_PER_TRADE_PCT: '0.01'
TRADING_SESSION_ONLY: '1'
TRADING_TRIGGER_SLIP_PCT: '0.004'
TRADING_UNIFIED_ENTRY: '1'
TRIGGER_ARM_INTERVAL_SECONDS: '20'
TRIGGER_ENABLED: '1'
TRIGGER_GAP_MAX: '35'
TRIGGER_GAP_MIN: '10.0'
TRIGGER_GAP_SQUEEZE_MIN: '150'
TRIGGER_GAP_SQUEEZE_RVOL: '5.0'
TRIGGER_INTERVAL_SECONDS: '4'
TRIGGER_MAX_ARMED: '10'
TRIGGER_MIN_DOLLAR_VOL: '8000'
TRIGGER_PRICE_MAX_AGE: '12'
TRIGGER_RVOL_MIN: '2.0'
TZ: America/New_York
WATCHER_ENABLED: '1'
WATCHER_INTERVAL_SECONDS: '15'
WATCHER_PRICE_MAX: '20'
WATCHER_PRICE_MIN: '2'
YOUTUBE_API_KEY: <FILL-ME-YOUTUBE-KEY>
volumes:
- /mnt/volume/Apps/momentum/data:/app/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
healthcheck:
test:
- CMD
- python
- -c
- import os; os.environ['PG_SKIP_SCHEMA']='1'; import datetime,sys; from research.multi_schema import open_research_db; r=open_research_db('market').execute('SELECT max(timestamp) FROM events').fetchall()[0][0]; sys.exit(0 if r and (datetime.datetime.now()-r).total_seconds()<300 else 1)
interval: 60s
timeout: 20s
retries: 5
start_period: 180s
dashboard:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- dashboard_api.py
environment:
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets/v2
ALPACA_DATA_FEED: sip
ALPACA_PAPER_SYNC_ENABLED: '1'
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
DEADMAN_DAILY_PING: '1'
DEADMAN_STALE_MIN: '5'
DISCOVER_INTERVAL_SECONDS: '120'
FMP_API_KEY: <FILL-ME-FMP-KEY>
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
LIVE_BARS_INTERVAL_SECONDS: '20'
LIVE_BARS_REFRESH_MINUTES: '20'
NEWS_CATALYST_SCORE_ENABLED: '1'
NEWS_DILUTION_VETO_ENABLED: '1'
NEWS_ENRICH_BATCH_LIMIT: '50'
NEWS_ENRICH_ENABLED: '1'
NEWS_ENRICH_INTERVAL_SECONDS: '120'
NEWS_ENRICH_LOOKBACK_HOURS: '12'
NEWS_FEEDS: prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
NEWS_LOOKBACK_HOURS: '8'
NEWS_RANK_BOOST: '2.0'
OLLAMA_ENABLED: '1'
OLLAMA_HOST: http://192.168.1.5:30068
OLLAMA_MODEL: qwen2.5:7b-instruct
OLLAMA_TEMPERATURE: '0.1'
OLLAMA_TIMEOUT_SECONDS: '60'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '1'
STRATEGY_SETUPS: opening_range_break
TELEGRAM_BOT_TOKEN: <FILL-ME-TELEGRAM-TOKEN>
TELEGRAM_CHAT_ID: <FILL-ME-TELEGRAM-CHAT-ID>
TRADING_AUTO_APPROVE: '1'
TRADING_BACKOUT_COOLDOWN_SECONDS: '180'
TRADING_BLOCK_REENTRY_AFTER_EXIT: '1'
TRADING_ENTRY_CONFIRM_BY_MINUTE: '0'
TRADING_ENTRY_FILL_MODEL: marketable
TRADING_ENTRY_INVALIDATE_PCT: '0.015'
TRADING_ENTRY_ORDER_TYPE: limit
TRADING_ENTRY_TIMEOUT_BARS: '2'
TRADING_EOD_FLATTEN_ENABLED: '1'
TRADING_EOD_FLATTEN_TIME: '15:55'
TRADING_EXECUTION_ENABLED: '1'
TRADING_EXIT_BREAKEVEN_R: '1.0'
TRADING_EXIT_PROFIT_TIERS: 8:3,15:9,25:18,40:30
TRADING_EXIT_TRAIL_AFTER_R: '1.0'
TRADING_EXIT_TRAIL_MODE: prior_low
TRADING_EXIT_TRAIL_R_STEP: '0.25'
TRADING_LIQUIDITY_MAX_VOLUME_PCT: '0.025'
TRADING_MAX_BACKOUTS_PER_SYMBOL: '3'
TRADING_MAX_CONCURRENT_POSITIONS: '10'
TRADING_MAX_DAILY_LOSS_PCT: '0.05'
TRADING_MAX_FRESH_ENTRIES_PER_DAY: '10'
TRADING_MAX_GROSS_NOTIONAL_PCT: '0.60'
TRADING_MAX_ORDERS_PER_TICK: '1'
TRADING_MAX_POSITION_PCT: '0.16'
TRADING_MAX_RISK_DOLLARS: '500'
TRADING_MIN_DAY_VOLUME: '300000'
TRADING_MIN_ENTRY_GAP_PCT: '0.10'
TRADING_MIN_QUALITY_SCORE: '0.60'
TRADING_PRICE_MAX: '20.0'
TRADING_PRICE_MIN: '2.0'
TRADING_REENTRY_MIN_LOSS_PCT: '0.01'
TRADING_REGIME_GATE_ENABLED: '1'
TRADING_REGIME_GATE_P_MIN: '0.5'
TRADING_REQUIRE_ABOVE_VWAP: '1'
TRADING_REWARD_MULTIPLE: '10.0'
TRADING_RISK_PER_TRADE_PCT: '0.01'
TRADING_SESSION_ONLY: '1'
TRADING_TRIGGER_SLIP_PCT: '0.004'
TRADING_UNIFIED_ENTRY: '1'
TRIGGER_ARM_INTERVAL_SECONDS: '20'
TRIGGER_ENABLED: '1'
TRIGGER_GAP_MAX: '35'
TRIGGER_GAP_MIN: '10.0'
TRIGGER_GAP_SQUEEZE_MIN: '150'
TRIGGER_GAP_SQUEEZE_RVOL: '5.0'
TRIGGER_INTERVAL_SECONDS: '4'
TRIGGER_MAX_ARMED: '10'
TRIGGER_MIN_DOLLAR_VOL: '8000'
TRIGGER_PRICE_MAX_AGE: '12'
TRIGGER_RVOL_MIN: '2.0'
TZ: America/New_York
WATCHER_ENABLED: '1'
WATCHER_INTERVAL_SECONDS: '15'
WATCHER_PRICE_MAX: '20'
WATCHER_PRICE_MIN: '2'
YOUTUBE_API_KEY: <FILL-ME-YOUTUBE-KEY>
DASHBOARD_HOST: 0.0.0.0
DASHBOARD_PORT: '8765'
DASHBOARD_TOKEN: <FILL-ME-DASHBOARD-TOKEN>
COMMAND_BUS_ENABLED: '1'
volumes:
- /mnt/volume/Apps/momentum/data:/app/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
ports:
- 8765:8765
qabot:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- telegram_bot.py
environment:
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets/v2
ALPACA_DATA_FEED: sip
ALPACA_PAPER_SYNC_ENABLED: '1'
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
DEADMAN_DAILY_PING: '1'
DEADMAN_STALE_MIN: '5'
DISCOVER_INTERVAL_SECONDS: '120'
FMP_API_KEY: <FILL-ME-FMP-KEY>
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
LIVE_BARS_INTERVAL_SECONDS: '20'
LIVE_BARS_REFRESH_MINUTES: '20'
NEWS_CATALYST_SCORE_ENABLED: '1'
NEWS_DILUTION_VETO_ENABLED: '1'
NEWS_ENRICH_BATCH_LIMIT: '50'
NEWS_ENRICH_ENABLED: '1'
NEWS_ENRICH_INTERVAL_SECONDS: '120'
NEWS_ENRICH_LOOKBACK_HOURS: '12'
NEWS_FEEDS: prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
NEWS_LOOKBACK_HOURS: '8'
NEWS_RANK_BOOST: '2.0'
OLLAMA_ENABLED: '1'
OLLAMA_HOST: http://192.168.1.5:30068
OLLAMA_MODEL: qwen2.5:7b-instruct
OLLAMA_TEMPERATURE: '0.1'
OLLAMA_TIMEOUT_SECONDS: '60'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '1'
STRATEGY_SETUPS: opening_range_break
TELEGRAM_BOT_TOKEN: <FILL-ME-TELEGRAM-TOKEN>
TELEGRAM_CHAT_ID: <FILL-ME-TELEGRAM-CHAT-ID>
TRADING_AUTO_APPROVE: '1'
TRADING_BACKOUT_COOLDOWN_SECONDS: '180'
TRADING_BLOCK_REENTRY_AFTER_EXIT: '1'
TRADING_ENTRY_CONFIRM_BY_MINUTE: '0'
TRADING_ENTRY_FILL_MODEL: marketable
TRADING_ENTRY_INVALIDATE_PCT: '0.015'
TRADING_ENTRY_ORDER_TYPE: limit
TRADING_ENTRY_TIMEOUT_BARS: '2'
TRADING_EOD_FLATTEN_ENABLED: '1'
TRADING_EOD_FLATTEN_TIME: '15:55'
TRADING_EXECUTION_ENABLED: '1'
TRADING_EXIT_BREAKEVEN_R: '1.0'
TRADING_EXIT_PROFIT_TIERS: 8:3,15:9,25:18,40:30
TRADING_EXIT_TRAIL_AFTER_R: '1.0'
TRADING_EXIT_TRAIL_MODE: prior_low
TRADING_EXIT_TRAIL_R_STEP: '0.25'
TRADING_LIQUIDITY_MAX_VOLUME_PCT: '0.025'
TRADING_MAX_BACKOUTS_PER_SYMBOL: '3'
TRADING_MAX_CONCURRENT_POSITIONS: '10'
TRADING_MAX_DAILY_LOSS_PCT: '0.05'
TRADING_MAX_FRESH_ENTRIES_PER_DAY: '10'
TRADING_MAX_GROSS_NOTIONAL_PCT: '0.60'
TRADING_MAX_ORDERS_PER_TICK: '1'
TRADING_MAX_POSITION_PCT: '0.16'
TRADING_MAX_RISK_DOLLARS: '500'
TRADING_MIN_DAY_VOLUME: '300000'
TRADING_MIN_ENTRY_GAP_PCT: '0.10'
TRADING_MIN_QUALITY_SCORE: '0.60'
TRADING_PRICE_MAX: '20.0'
TRADING_PRICE_MIN: '2.0'
TRADING_REENTRY_MIN_LOSS_PCT: '0.01'
TRADING_REGIME_GATE_ENABLED: '1'
TRADING_REGIME_GATE_P_MIN: '0.5'
TRADING_REQUIRE_ABOVE_VWAP: '1'
TRADING_REWARD_MULTIPLE: '10.0'
TRADING_RISK_PER_TRADE_PCT: '0.01'
TRADING_SESSION_ONLY: '1'
TRADING_TRIGGER_SLIP_PCT: '0.004'
TRADING_UNIFIED_ENTRY: '1'
TRIGGER_ARM_INTERVAL_SECONDS: '20'
TRIGGER_ENABLED: '1'
TRIGGER_GAP_MAX: '35'
TRIGGER_GAP_MIN: '10.0'
TRIGGER_GAP_SQUEEZE_MIN: '150'
TRIGGER_GAP_SQUEEZE_RVOL: '5.0'
TRIGGER_INTERVAL_SECONDS: '4'
TRIGGER_MAX_ARMED: '10'
TRIGGER_MIN_DOLLAR_VOL: '8000'
TRIGGER_PRICE_MAX_AGE: '12'
TRIGGER_RVOL_MIN: '2.0'
TZ: America/New_York
WATCHER_ENABLED: '1'
WATCHER_INTERVAL_SECONDS: '15'
WATCHER_PRICE_MAX: '20'
WATCHER_PRICE_MIN: '2'
YOUTUBE_API_KEY: <FILL-ME-YOUTUBE-KEY>
volumes:
- /mnt/volume/Apps/momentum/data:/app/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
transcripts:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- -m
- youtube_claims.run
- run
environment:
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets/v2
ALPACA_DATA_FEED: sip
ALPACA_PAPER_SYNC_ENABLED: '1'
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
DEADMAN_DAILY_PING: '1'
DEADMAN_STALE_MIN: '5'
DISCOVER_INTERVAL_SECONDS: '120'
FMP_API_KEY: <FILL-ME-FMP-KEY>
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
LIVE_BARS_INTERVAL_SECONDS: '20'
LIVE_BARS_REFRESH_MINUTES: '20'
NEWS_CATALYST_SCORE_ENABLED: '1'
NEWS_DILUTION_VETO_ENABLED: '1'
NEWS_ENRICH_BATCH_LIMIT: '50'
NEWS_ENRICH_ENABLED: '1'
NEWS_ENRICH_INTERVAL_SECONDS: '120'
NEWS_ENRICH_LOOKBACK_HOURS: '12'
NEWS_FEEDS: prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
NEWS_LOOKBACK_HOURS: '8'
NEWS_RANK_BOOST: '2.0'
OLLAMA_ENABLED: '1'
OLLAMA_HOST: http://192.168.1.5:30068
OLLAMA_MODEL: qwen2.5:7b-instruct
OLLAMA_TEMPERATURE: '0.1'
OLLAMA_TIMEOUT_SECONDS: '60'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '1'
STRATEGY_SETUPS: opening_range_break
TELEGRAM_BOT_TOKEN: <FILL-ME-TELEGRAM-TOKEN>
TELEGRAM_CHAT_ID: <FILL-ME-TELEGRAM-CHAT-ID>
TRADING_AUTO_APPROVE: '1'
TRADING_BACKOUT_COOLDOWN_SECONDS: '180'
TRADING_BLOCK_REENTRY_AFTER_EXIT: '1'
TRADING_ENTRY_CONFIRM_BY_MINUTE: '0'
TRADING_ENTRY_FILL_MODEL: marketable
TRADING_ENTRY_INVALIDATE_PCT: '0.015'
TRADING_ENTRY_ORDER_TYPE: limit
TRADING_ENTRY_TIMEOUT_BARS: '2'
TRADING_EOD_FLATTEN_ENABLED: '1'
TRADING_EOD_FLATTEN_TIME: '15:55'
TRADING_EXECUTION_ENABLED: '1'
TRADING_EXIT_BREAKEVEN_R: '1.0'
TRADING_EXIT_PROFIT_TIERS: 8:3,15:9,25:18,40:30
TRADING_EXIT_TRAIL_AFTER_R: '1.0'
TRADING_EXIT_TRAIL_MODE: prior_low
TRADING_EXIT_TRAIL_R_STEP: '0.25'
TRADING_LIQUIDITY_MAX_VOLUME_PCT: '0.025'
TRADING_MAX_BACKOUTS_PER_SYMBOL: '3'
TRADING_MAX_CONCURRENT_POSITIONS: '10'
TRADING_MAX_DAILY_LOSS_PCT: '0.05'
TRADING_MAX_FRESH_ENTRIES_PER_DAY: '10'
TRADING_MAX_GROSS_NOTIONAL_PCT: '0.60'
TRADING_MAX_ORDERS_PER_TICK: '1'
TRADING_MAX_POSITION_PCT: '0.16'
TRADING_MAX_RISK_DOLLARS: '500'
TRADING_MIN_DAY_VOLUME: '300000'
TRADING_MIN_ENTRY_GAP_PCT: '0.10'
TRADING_MIN_QUALITY_SCORE: '0.60'
TRADING_PRICE_MAX: '20.0'
TRADING_PRICE_MIN: '2.0'
TRADING_REENTRY_MIN_LOSS_PCT: '0.01'
TRADING_REGIME_GATE_ENABLED: '1'
TRADING_REGIME_GATE_P_MIN: '0.5'
TRADING_REQUIRE_ABOVE_VWAP: '1'
TRADING_REWARD_MULTIPLE: '10.0'
TRADING_RISK_PER_TRADE_PCT: '0.01'
TRADING_SESSION_ONLY: '1'
TRADING_TRIGGER_SLIP_PCT: '0.004'
TRADING_UNIFIED_ENTRY: '1'
TRIGGER_ARM_INTERVAL_SECONDS: '20'
TRIGGER_ENABLED: '1'
TRIGGER_GAP_MAX: '35'
TRIGGER_GAP_MIN: '10.0'
TRIGGER_GAP_SQUEEZE_MIN: '150'
TRIGGER_GAP_SQUEEZE_RVOL: '5.0'
TRIGGER_INTERVAL_SECONDS: '4'
TRIGGER_MAX_ARMED: '10'
TRIGGER_MIN_DOLLAR_VOL: '8000'
TRIGGER_PRICE_MAX_AGE: '12'
TRIGGER_RVOL_MIN: '2.0'
TZ: America/New_York
WATCHER_ENABLED: '1'
WATCHER_INTERVAL_SECONDS: '15'
WATCHER_PRICE_MAX: '20'
WATCHER_PRICE_MIN: '2'
YOUTUBE_API_KEY: <FILL-ME-YOUTUBE-KEY>
volumes:
- /mnt/volume/Apps/momentum/data:/app/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
admin:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- admin_api.py
environment:
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets/v2
ALPACA_DATA_FEED: sip
ALPACA_PAPER_SYNC_ENABLED: '1'
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
DEADMAN_DAILY_PING: '1'
DEADMAN_STALE_MIN: '5'
DISCOVER_INTERVAL_SECONDS: '120'
FMP_API_KEY: <FILL-ME-FMP-KEY>
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
LIVE_BARS_INTERVAL_SECONDS: '20'
LIVE_BARS_REFRESH_MINUTES: '20'
NEWS_CATALYST_SCORE_ENABLED: '1'
NEWS_DILUTION_VETO_ENABLED: '1'
NEWS_ENRICH_BATCH_LIMIT: '50'
NEWS_ENRICH_ENABLED: '1'
NEWS_ENRICH_INTERVAL_SECONDS: '120'
NEWS_ENRICH_LOOKBACK_HOURS: '12'
NEWS_FEEDS: prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
NEWS_LOOKBACK_HOURS: '8'
NEWS_RANK_BOOST: '2.0'
OLLAMA_ENABLED: '1'
OLLAMA_HOST: http://192.168.1.5:30068
OLLAMA_MODEL: qwen2.5:7b-instruct
OLLAMA_TEMPERATURE: '0.1'
OLLAMA_TIMEOUT_SECONDS: '60'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '1'
STRATEGY_SETUPS: opening_range_break
TELEGRAM_BOT_TOKEN: <FILL-ME-TELEGRAM-TOKEN>
TELEGRAM_CHAT_ID: <FILL-ME-TELEGRAM-CHAT-ID>
TRADING_AUTO_APPROVE: '1'
TRADING_BACKOUT_COOLDOWN_SECONDS: '180'
TRADING_BLOCK_REENTRY_AFTER_EXIT: '1'
TRADING_ENTRY_CONFIRM_BY_MINUTE: '0'
TRADING_ENTRY_FILL_MODEL: marketable
TRADING_ENTRY_INVALIDATE_PCT: '0.015'
TRADING_ENTRY_ORDER_TYPE: limit
TRADING_ENTRY_TIMEOUT_BARS: '2'
TRADING_EOD_FLATTEN_ENABLED: '1'
TRADING_EOD_FLATTEN_TIME: '15:55'
TRADING_EXECUTION_ENABLED: '1'
TRADING_EXIT_BREAKEVEN_R: '1.0'
TRADING_EXIT_PROFIT_TIERS: 8:3,15:9,25:18,40:30
TRADING_EXIT_TRAIL_AFTER_R: '1.0'
TRADING_EXIT_TRAIL_MODE: prior_low
TRADING_EXIT_TRAIL_R_STEP: '0.25'
TRADING_LIQUIDITY_MAX_VOLUME_PCT: '0.025'
TRADING_MAX_BACKOUTS_PER_SYMBOL: '3'
TRADING_MAX_CONCURRENT_POSITIONS: '10'
TRADING_MAX_DAILY_LOSS_PCT: '0.05'
TRADING_MAX_FRESH_ENTRIES_PER_DAY: '10'
TRADING_MAX_GROSS_NOTIONAL_PCT: '0.60'
TRADING_MAX_ORDERS_PER_TICK: '1'
TRADING_MAX_POSITION_PCT: '0.16'
TRADING_MAX_RISK_DOLLARS: '500'
TRADING_MIN_DAY_VOLUME: '300000'
TRADING_MIN_ENTRY_GAP_PCT: '0.10'
TRADING_MIN_QUALITY_SCORE: '0.60'
TRADING_PRICE_MAX: '20.0'
TRADING_PRICE_MIN: '2.0'
TRADING_REENTRY_MIN_LOSS_PCT: '0.01'
TRADING_REGIME_GATE_ENABLED: '1'
TRADING_REGIME_GATE_P_MIN: '0.5'
TRADING_REQUIRE_ABOVE_VWAP: '1'
TRADING_REWARD_MULTIPLE: '10.0'
TRADING_RISK_PER_TRADE_PCT: '0.01'
TRADING_SESSION_ONLY: '1'
TRADING_TRIGGER_SLIP_PCT: '0.004'
TRADING_UNIFIED_ENTRY: '1'
TRIGGER_ARM_INTERVAL_SECONDS: '20'
TRIGGER_ENABLED: '1'
TRIGGER_GAP_MAX: '35'
TRIGGER_GAP_MIN: '10.0'
TRIGGER_GAP_SQUEEZE_MIN: '150'
TRIGGER_GAP_SQUEEZE_RVOL: '5.0'
TRIGGER_INTERVAL_SECONDS: '4'
TRIGGER_MAX_ARMED: '10'
TRIGGER_MIN_DOLLAR_VOL: '8000'
TRIGGER_PRICE_MAX_AGE: '12'
TRIGGER_RVOL_MIN: '2.0'
TZ: America/New_York
WATCHER_ENABLED: '1'
WATCHER_INTERVAL_SECONDS: '15'
WATCHER_PRICE_MAX: '20'
WATCHER_PRICE_MIN: '2'
YOUTUBE_API_KEY: <FILL-ME-YOUTUBE-KEY>
ADMIN_PORT: '8767'
ADMIN_TOKEN: <FILL-ME-ADMIN-TOKEN>
volumes:
- /mnt/volume/Apps/momentum/data:/app/data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
ports:
- 8767:8767
scheduler:
image: docker.io/fez5587/momentum-app:latest
command:
- /bin/sh
- -c
- "echo \"[scheduler] up; fires 20:00 ET Mon-Fri\"\nwhile true; do\n if [ \"$$(date +%H:%M)\" = \"20:00\" ] && [ \"$$(date +%u)\" -le 5 ]; then\n python -m research.premarket_eval || echo \"[scheduler] eval FAILED\"\n python -m research.ingestion.market_context || echo \"[scheduler] market_context FAILED\"\n python -m research.eod_reconcile || echo \"[scheduler] reconcile FAILED\"\n python eod_replay.py || echo \"[scheduler] eod_replay FAILED\"\n python nightly_tune.py || echo \"[scheduler] nightly_tune FAILED\"\n python -m research.regime build-features || echo \"[scheduler] regime build FAILED\"\n python -m research.regime score --model threshold_v1 || echo \"[scheduler] regime threshold FAILED\"\n python -m research.regime score --model meta_v1 || echo \"[scheduler] regime meta FAILED\"\n python -m research.experiments run || echo \"[scheduler] experiments run FAILED\"\n python -m research.experiments adjudicate || echo \"[scheduler] experiments adjudicate FAILED\"\n sleep 120\n fi\n sleep 20\ndone\n"
environment:
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets/v2
ALPACA_DATA_FEED: sip
ALPACA_PAPER_SYNC_ENABLED: '1'
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
DEADMAN_DAILY_PING: '1'
DEADMAN_STALE_MIN: '5'
DISCOVER_INTERVAL_SECONDS: '120'
FMP_API_KEY: <FILL-ME-FMP-KEY>
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
LIVE_BARS_INTERVAL_SECONDS: '20'
LIVE_BARS_REFRESH_MINUTES: '20'
NEWS_CATALYST_SCORE_ENABLED: '1'
NEWS_DILUTION_VETO_ENABLED: '1'
NEWS_ENRICH_BATCH_LIMIT: '50'
NEWS_ENRICH_ENABLED: '1'
NEWS_ENRICH_INTERVAL_SECONDS: '120'
NEWS_ENRICH_LOOKBACK_HOURS: '12'
NEWS_FEEDS: prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
NEWS_LOOKBACK_HOURS: '8'
NEWS_RANK_BOOST: '2.0'
OLLAMA_ENABLED: '1'
OLLAMA_HOST: http://192.168.1.5:30068
OLLAMA_MODEL: qwen2.5:7b-instruct
OLLAMA_TEMPERATURE: '0.1'
OLLAMA_TIMEOUT_SECONDS: '60'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '1'
STRATEGY_SETUPS: opening_range_break
TELEGRAM_BOT_TOKEN: <FILL-ME-TELEGRAM-TOKEN>
TELEGRAM_CHAT_ID: <FILL-ME-TELEGRAM-CHAT-ID>
TRADING_AUTO_APPROVE: '1'
TRADING_BACKOUT_COOLDOWN_SECONDS: '180'
TRADING_BLOCK_REENTRY_AFTER_EXIT: '1'
TRADING_ENTRY_CONFIRM_BY_MINUTE: '0'
TRADING_ENTRY_FILL_MODEL: marketable
TRADING_ENTRY_INVALIDATE_PCT: '0.015'
TRADING_ENTRY_ORDER_TYPE: limit
TRADING_ENTRY_TIMEOUT_BARS: '2'
TRADING_EOD_FLATTEN_ENABLED: '1'
TRADING_EOD_FLATTEN_TIME: '15:55'
TRADING_EXECUTION_ENABLED: '1'
TRADING_EXIT_BREAKEVEN_R: '1.0'
TRADING_EXIT_PROFIT_TIERS: 8:3,15:9,25:18,40:30
TRADING_EXIT_TRAIL_AFTER_R: '1.0'
TRADING_EXIT_TRAIL_MODE: prior_low
TRADING_EXIT_TRAIL_R_STEP: '0.25'
TRADING_LIQUIDITY_MAX_VOLUME_PCT: '0.025'
TRADING_MAX_BACKOUTS_PER_SYMBOL: '3'
TRADING_MAX_CONCURRENT_POSITIONS: '10'
TRADING_MAX_DAILY_LOSS_PCT: '0.05'
TRADING_MAX_FRESH_ENTRIES_PER_DAY: '10'
TRADING_MAX_GROSS_NOTIONAL_PCT: '0.60'
TRADING_MAX_ORDERS_PER_TICK: '1'
TRADING_MAX_POSITION_PCT: '0.16'
TRADING_MAX_RISK_DOLLARS: '500'
TRADING_MIN_DAY_VOLUME: '300000'
TRADING_MIN_ENTRY_GAP_PCT: '0.10'
TRADING_MIN_QUALITY_SCORE: '0.60'
TRADING_PRICE_MAX: '20.0'
TRADING_PRICE_MIN: '2.0'
TRADING_REENTRY_MIN_LOSS_PCT: '0.01'
TRADING_REGIME_GATE_ENABLED: '1'
TRADING_REGIME_GATE_P_MIN: '0.5'
TRADING_REQUIRE_ABOVE_VWAP: '1'
TRADING_REWARD_MULTIPLE: '10.0'
TRADING_RISK_PER_TRADE_PCT: '0.01'
TRADING_SESSION_ONLY: '1'
TRADING_TRIGGER_SLIP_PCT: '0.004'
TRADING_UNIFIED_ENTRY: '1'
TRIGGER_ARM_INTERVAL_SECONDS: '20'
TRIGGER_ENABLED: '1'
TRIGGER_GAP_MAX: '35'
TRIGGER_GAP_MIN: '10.0'
TRIGGER_GAP_SQUEEZE_MIN: '150'
TRIGGER_GAP_SQUEEZE_RVOL: '5.0'
TRIGGER_INTERVAL_SECONDS: '4'
TRIGGER_MAX_ARMED: '10'
TRIGGER_MIN_DOLLAR_VOL: '8000'
TRIGGER_PRICE_MAX_AGE: '12'
TRIGGER_RVOL_MIN: '2.0'
TZ: America/New_York
WATCHER_ENABLED: '1'
WATCHER_INTERVAL_SECONDS: '15'
WATCHER_PRICE_MAX: '20'
WATCHER_PRICE_MIN: '2'
YOUTUBE_API_KEY: <FILL-ME-YOUTUBE-KEY>
volumes:
- /mnt/volume/Apps/momentum/data:/app/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
db-backup:
image: postgres:18
restart: unless-stopped
environment:
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
BACKUP_DIR: /backups
BACKUP_KEEP_DAYS: '14'
TZ: America/New_York
volumes:
- /mnt/volume/Apps/momentum/data/backups:/backups
depends_on:
postgres:
condition: service_healthy
command:
- /bin/bash
- -c
- "set -o pipefail\necho \"[backup] up; fires 20:10 ET Mon-Fri\"\nwhile true; do\n if [ \"$$(date +%H:%M)\" = \"20:10\" ] && [ \"$$(date +%u)\" -le 5 ]; then\n out=\"$$BACKUP_DIR/momentum-$$(date +%F).sql.gz\"\n mkdir -p \"$$BACKUP_DIR\" && pg_dump \"$$DATABASE_URL\" | gzip > \"$$out.tmp\" && gunzip -t \"$$out.tmp\" && mv \"$$out.tmp\" \"$$out\" && echo \"[backup] OK\" || echo \"[backup] FAILED\"\n sleep 120\n fi\n sleep 20\ndone\n"