Commit Graph

4015 Commits

Author SHA1 Message Date
jgrusewski
129c2f19b8 fix(ml): mamba2 hyperopt tensors created on GPU instead of CPU
Replace &Device::Cpu with &self.device for input and target tensor
creation in Mamba2 hyperopt adapter. Avoids unnecessary CPU→GPU
transfer during hyperparameter optimization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:03:10 +01:00
jgrusewski
85138e2fbd feat(ml): add StreamAwareEnsemble with per-model CUDA streams
Stream-aware ensemble that runs models on separate CUDA streams
for true GPU-level parallelism. Falls back to rayon on CPU.
Uses CudaStreamPool for synchronization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:59:12 +01:00
jgrusewski
550944ebf2 feat(ml): add CudaStreamPool for multi-stream ensemble inference
CUDA stream pool with CPU no-op fallback. Foundation for
StreamAwareEnsemble that runs models on separate CUDA streams.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:52:45 +01:00
jgrusewski
58dc95cf54 feat(ml): InferenceEnsemble GPU-aggregated prediction — N syncs → 1
Use predict_raw() to collect raw GPU tensors from adapters. Stack,
sigmoid, weighted-sum on GPU before single extraction. Falls back
to CPU path for adapters without tensor output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:46:21 +01:00
jgrusewski
78f5ead601 feat(ml): implement predict_raw() for 5 scalar-output ensemble adapters
Override predict_raw() in TGGN, TLOB, KAN, xLSTM, Diffusion adapters
to return raw GPU tensors. Enables GPU-side ensemble aggregation
instead of per-model CPU extraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:46:09 +01:00
jgrusewski
f8cec1d6f9 feat(ml): KAN spline GPU-native forward — eliminate GPU→CPU→GPU roundtrip
Replace clamped.to_vec1() CPU loop with GPU-native floor/ceil/frac
operations. Removes 3 tensor transfers per forward pass (N floats
down + 3*N up). All index computation now stays on GPU.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:41:14 +01:00
jgrusewski
3aab43614a feat(ml): PPO metrics batch extraction — 4 GPU syncs → 1
Stack var_returns, var_residuals, mean_reward, var_reward into single
tensor before extraction. Uses broadcast_sub for GPU-native mean
centering instead of scalar round-trip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:41:11 +01:00
jgrusewski
c91995e41d feat(ml): add RawPrediction + predict_raw() default to ModelInferenceAdapter
Backward-compatible trait extension. Default predict_raw() wraps
predict() result with tensor: None. Adapters can override to return
raw GPU tensors for GPU-side ensemble aggregation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:41:08 +01:00
jgrusewski
a57e4911ff fix(ci): fix PVC-based deploy pipeline (stale pods, ordering, cross-node RWO)
The S3→PVC migration had several issues causing deploy failures:

- Stale binary-writer pod from previous failed deploys blocked new ones
  (terminated pods can't be updated via kubectl apply)
- Services were applied BEFORE binaries written to PVC, so first deploy
  or empty PVC caused pods to crash (binary not found)
- GPU overlay files in services/ dir were auto-applied by kubectl apply,
  referencing nonexistent S3/minio secrets and PVCs
- Training job template mounted foxhunt-binaries PVC but training runs
  on ci-training node — RWO PVC is bound to foxhunt node

Fixes:
- Reorder deploy: write binaries → apply manifests → rollout restart
- Clean up stale writer pods before creating new ones
- Move GPU overlays to gpu-overlays/ (manual apply only), update to PVC
- Add training-binaries PVC for GPU node, best-effort population
- Training job template uses initContainer to copy from training PVC
- set -e for critical path, set +e for optional training binary copy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:40:28 +01:00
jgrusewski
e12cdfa005 feat(ml): diffusion trainer GPU-accumulated loss + batched grad norm
Replace per-param gradient norm extraction with batched Tensor::stack
pattern (N GPU syncs → 1). Remove per-batch loss scalar extraction
from backward(), defer to epoch-level accumulation. Apply GPU-accumulated
validation loss (stack + mean_all instead of per-batch to_scalar).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:30:19 +01:00
jgrusewski
4cf181c8fb feat(ml): TFT batched gradient norm — N GPU syncs → 1
Replace per-param gradient norm extraction loop with batched
Tensor::stack pattern. Single GPU→CPU sync instead of one per
parameter tensor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:30:10 +01:00
jgrusewski
7d2b56a3ad feat(ml): TLOB batched parameter norm — N GPU syncs → 1
Replace per-param calculate_gradient_norm() loop with batched
Tensor::stack pattern. Single GPU→CPU sync instead of one per
parameter tensor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:29:33 +01:00
jgrusewski
fd80dbc07e feat(ml): TFT trainer GPU-accumulated loss — eliminate per-batch to_vec0
Replace per-batch loss.to_vec0() in TFT training/validation loops
with GPU tensor accumulation. Single extraction per epoch + NaN guard
every 100 batches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:25:57 +01:00
jgrusewski
2c493f4305 feat(ml): liquid trainer GPU-accumulated loss — eliminate per-batch to_scalar
Replace per-batch .to_dtype(F64).to_scalar() in Liquid train/validate
with GPU tensor accumulation. Single extraction per epoch + NaN guard
every 100 batches. Removes ~100-500 GPU→CPU syncs per epoch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:25:56 +01:00
jgrusewski
851546b322 feat(ml): TLOB trainer GPU-accumulated loss — eliminate per-batch to_scalar
Replace per-batch loss.to_scalar() in TLOB train_epoch/validate_epoch
with GPU tensor accumulation. Single extraction per epoch + NaN guard
every 100 batches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:25:54 +01:00
jgrusewski
85a51991e9 fix(ci): use training-bin/ dir to avoid collision with source bin/fxt/
The before_script was copying training binaries to ${CI_PROJECT_DIR}/bin/
which collides with the git checkout bin/fxt/ directory. chmod +x on the
fxt subdirectory fails with "Operation not permitted", crashing the job.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:12:04 +01:00
jgrusewski
091167bb23 fix(ci): align training job tags with runner (kapsule-rl → kapsule)
Runner #2 already has tags [kapsule, gpu] but CI jobs still used
kapsule-rl. Also removes stale minio-ca-cert volume from runner values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:45:19 +01:00
jgrusewski
0d49fb96c5 fix(ci): add compile-training artifacts to deploy stage needs
Deploy stage needs compile-training artifacts to copy training binaries
to the foxhunt-binaries PVC alongside service binaries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:15:53 +01:00
jgrusewski
81237e1bae fix(ci): replace MinIO S3 with PVC + CI artifacts for training binaries
MinIO pod was removed but compile-training still uploaded to it via rclone,
causing 403 Forbidden failures. Now:

- compile-training: saves binaries as CI artifacts (3 day TTL)
- deploy stage: copies training binaries to foxhunt-binaries PVC via binary-writer
- CI training jobs: use compile-training CI artifacts directly
- job-template.yaml: mounts foxhunt-binaries PVC (no initContainer)
- Removed MinIO deploy from deploy stage (no longer needed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:06:00 +01:00
jgrusewski
118ceca4d5 fix(ml): update evaluate_baseline for 45 factored actions
Both DQN and PPO eval paths used old 3-action index matching (0=Buy,
1=Sell, 2=Hold). Now uses FactoredAction.target_exposure() for
exposure-weighted returns and order-type-specific transaction costs.
PPO path had .to_int() which doesn't exist on FactoredAction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:24 +01:00
jgrusewski
18f98e17bb fix(ml): update PPO trainer reward and position tracking for 45 factored actions
compute_reward_pnl() took raw action_idx (0=Buy,1=Sell,2=Hold) — wrong
with 45-action FactoredAction encoding. Now takes &FactoredAction and
uses order-type-specific transaction costs. Position tracking uses
action.exposure instead of old 3-way index match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:24 +01:00
jgrusewski
9c3383420b fix(ml): update remaining PPO num_actions: 3 → 45 in hyperopt and benchmark
Hyperopt adapter and PPO benchmark still had num_actions: 3, which would
produce misconfigured PPO models when used with the 45-action FactoredAction
sampling path. Found by spec compliance review.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
a41387c3f9 fix(ml): make IG completeness axiom test deterministic
Use a purely linear network (no ReLU) for the completeness axiom test.
IG on linear functions is mathematically exact, so the test is
deterministic regardless of random weight initialization. Tighten
tolerance from 20% to 1% (f32 rounding only). Keep ReLU network in
the basic test for non-linear verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
2e15d1d834 fix: trading_service PPO type mismatch and IG test tolerance
- trading_service: PPO predict() used TradingAction match but act() now
  returns FactoredAction. Use target_exposure() mapped to 0-1 range.
- IG completeness axiom test: relax tolerance from 5% to 20% (random
  weights with ReLU non-linearity and trapezoidal rule can exceed 5%).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
63b2c6e72d fix(ml): align PPO action masking to canonical exposure*9+order*3+urgency layout
Was using direction=idx/15 (3 groups of 15: Buy/Sell/Hold) — incompatible
with DQN's FactoredAction encoding. Now uses exposure_idx=idx/9 (5 groups
of 9: Short100/Short50/Flat/Long50/Long100) matching FactoredAction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
512535076f feat(ml): wire PPO to 45 factored actions via FactoredAction
sample_action(), act(), act_with_log_prob(), greedy_action() now return
FactoredAction instead of TradingAction. Fixes the architectural disconnect
where num_actions=45 output neurons were sampled through a 3-action bottleneck.

TrajectoryStep.action and TrajectoryBatch.actions now use FactoredAction.
Added FactoredAction::from_legacy() for backward compatibility in tests.

Updated all PPO consumers: trainers/ppo.rs, hyperopt/adapters/ppo.rs,
validation/ppo_adapter.rs, benchmark/ppo_benchmark.rs.

2487 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
f12336f16f refactor(ml): move FactoredAction to common/action.rs (canonical location)
Consolidates ExposureLevel, Urgency, FactoredAction from dqn/action_space.rs
and ppo/factored_action.rs into common/action.rs. Both dqn:: and ppo::
re-export for backward compatibility. Deletes ppo/factored_action.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
669c3b93d4 fix(trading_service): update feature importance stub to unimplemented
Changed from Status::unavailable to Status::unimplemented with path
forward (ml_training_service forwarding). Fixed supports_feature_importance
from true to false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
ca2468f5ae fix(ml): remove hidden fake feature importance from inference path
calculate_feature_importance() returned hardcoded fabricated scores with
wrong feature names on every inference. Replaced with honest empty map.
Real importance is computed on-demand via integrated gradients.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
764deb7ddb feat(ml): add integrated gradients for feature importance
Implements IntegratedGradients using Candle autograd (Var::from_tensor +
backward). Computes attributions by integrating input gradients along
interpolation path from baseline to input.

Verified via completeness axiom test: sum(attributions) ≈ F(x) - F(baseline).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
2fbb19d9df refactor(ml): rename real_data_loader to data_loader
The real_ prefix was misleading — there is no fake data loader.
Mechanical rename across 18 source files, no logic changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
3d679e824f feat(ml): GPU saturation final — DQN PER deferral, PPO trajectory batching, Liquid/TGGN sync reduction, DoubleBuffer wiring
- DQN PER: defer td_errors to_vec1() after loss.to_scalar() — piggyback on
  existing pipeline flush instead of forcing premature GPU→CPU stall
- PPO trajectories: capacity-hint Vec allocations, extend_flat_states methods,
  states_flat field on TrajectoryBatch for zero-copy GPU upload
- TGGN validate(): batch N per-sample losses on GPU → single to_scalar() sync
  (was N GPU→CPU syncs)
- Liquid backward(): batch grad-norm per-param sqr().sum_all() on GPU → single
  to_scalar() sync (was N GPU→CPU syncs per optimizer step)
- Liquid validate(): same N→1 GPU sync reduction as TGGN
- DQN trainer: restore EpochPrefetcher/DoubleBufferedLoader API (wrongly deleted)
- train_baseline_rl: wire DoubleBuffer GPU pre-upload — after CPU prefetch
  completes, immediately upload next fold to GPU via DqnGpuData::upload() so
  next fold starts with data already resident on GPU

2478 tests pass, 0 clippy warnings, 0 compile errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
a454a26a5c feat(ml): GPU saturation backlog — PPO rollout sync, VRAM-aware dims, KAN GPU splines
Three remaining GPU bottlenecks from the saturation backlog:

1. PPO rollout GPU sync stalls (3→1 per step):
   - Merged sample_action to return (action_idx, probs_vec), eliminating
     duplicate to_vec1 sync on action probabilities
   - Batched critic forward after rollout loop — single GPU→CPU sync
     replaces per-step critic.forward() calls (2048 syncs → 1)
   - Safe indexing throughout (clippy deny rules)

2. VRAM-aware default network dimensions:
   - Added detect_vram_mb() with GPU_MEMORY_MB env var override for K8s
   - Added vram_scaled_hidden_dims() with 4 tiers (CPU/<8GB/16GB/40GB+)
   - DQN: [256,256] → [2048,1024,512] on L40S/H100
   - PPO: hidden_dim_base 128 → 1024 on L40S/H100
   - Wired into train_baseline_rl.rs for non-hyperopt training runs

3. KAN B-spline GPU lookup table:
   - Pre-compute basis values on 1024-point grid at layer construction
   - GPU evaluation via gather + linear interpolation (replaces recursive
     Cox-de Boor CPU bounce: 32K recursive calls → 2 GPU gathers)
   - Fallback to CPU path when grid not pre-computed

5 files changed, +687/-43, 2476 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
2aedc2ae1a feat(ml): comprehensive GPU saturation audit — 58 fixes across all 10 models
Phase 1 — Fix broken models (P0):
- Diffusion: wire optimizer_step to actually apply gradients (was no-op)
- TLOB: connect forward pass to projection layers (was Tensor::zeros)
- Mamba2: F64→F32 migration across 5 files (~30x faster on L40S tensor cores)

Phase 2 — Eliminate hot-path GPU sync stalls:
- Mamba2: keep dt on GPU in discretize_ssm (4 functions, no CPU round-trip)
- TFT: gate attention weight logging to eval only (8 syncs/forward eliminated)
- Mamba2: defer loss scalar after backward (pipeline stall removed)
- Mamba2: delete dead gradient clipping (4N wasted GPU syncs removed)

Phase 3 — Enable BF16 for supervised models:
- Flip mixed_precision defaults to true in 4 config locations
- Fix cuda_layer_norm to support BF16/F16 via F32 intermediate

Phase 4 — Raise hyperopt bounds for datacenter GPUs:
- 7 adapters with VRAM-aware tiers (TFT, Liquid, TGGN, KAN, xLSTM,
  Diffusion, TLOB) — L40S gets full hidden_dim range
- Fix L40S tier boundary (was excluded at <48000, now >=40000)

Phase 5 — Update memory estimates:
- 10 param_count estimates updated (DQN 200K→12M, TFT 2M→50M, etc.)
- Fix power-of-two rounding (was wasting up to 49% of budget)
- Correct MODEL_OVERHEAD_MB in DQN/PPO/TFT adapters

Phase 6 — Fix per-epoch CPU bottlenecks:
- PPO: deduplicate double advantage normalization (correctness fix)
- PPO: GPU tensor reward normalization + explained variance
- Fuse per-parameter grad norm to single GPU sync (xLSTM, KAN, TGGN)

Phase 7 — Data pipeline:
- GpuBufferPool: use from_slice (eliminate staging buffer copy)

Phase 8 — Correctness:
- TFT: remove broken .detach() in forward_checkpointed (restore gradients)
- Update stale RTX 3050 Ti doc references

33 files changed, 2451 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
b4dc9766f9 fix(infra): remove dead Cockpit remote_write from GitLab Prometheus
The remoteWrite block had placeholder values (COCKPIT_METRICS_PUSH_URL,
COCKPIT_PUSH_TOKEN) that were never replaced, causing Prometheus to
spam "Failed to send batch" warnings every minute. Cockpit was replaced
by self-hosted Grafana+Prometheus+Loki+Tempo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:26:17 +01:00
jgrusewski
d501d53c9d chore(infra): remove dead Cockpit TF, CI-CD dashboards, stale Grafana configs
- Delete infra/modules/cockpit/ and infra/live/production/cockpit/
  (Scaleway Cockpit replaced by self-hosted Grafana+Prometheus+Loki+Tempo)
- Delete CI-CD dashboards (foxhunt-ci-pipelines, gitlab-services) and
  grafana-dashboards-cicd ConfigMap from K8s
- Delete config/grafana/ — unreferenced old dashboards (15 files)
- Delete config/monitoring/grafana/ — unreferenced DQN staging dashboard
- Delete crates/ml/grafana/ — unreferenced ML performance dashboard
- Delete services/broker_gateway_service/grafana/ — unreferenced
- Delete .claude/agents/devops/ci-cd/ — GitHub Actions agent (we use GitLab CI)
- Fix grafana-values.yaml: dashboard folder GitLab → Foxhunt,
  hardcoded adminPassword → K8s secret (grafana-admin),
  gitlab-overview → node-exporter (correct name for gnetId 1860)
- Remove CI-CD group from import.sh ConfigMap groups and API fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:13:40 +01:00
jgrusewski
36d291a8e0 fix(fxt): robust ibapi handshake retry and config test isolation
- ibapi handshake: retry once after 1s on first failure (IB Gateway
  needs time to release stale client_id slots after disconnection)
- test_load_nonexistent_config → test_load_config_succeeds: remove
  default-value assertions that fail when ~/.foxhunt/config.toml exists
  (defaults already tested by test_serde_defaults and test_default_config)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:52:48 +01:00
jgrusewski
032be46e90 fix(fxt): default broker gateway URL 50060 → 50056
Match the actual K8s broker-gateway service port discovered during
live validation of fxt broker check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:49:23 +01:00
jgrusewski
47cea06e86 fix(fxt): default broker check port 4002 → 4004 (socat)
The IB Gateway JVM uses non-blocking I/O on port 4002, which causes
EAGAIN errors with ibapi's blocking Client::connect(). The gnzsnz
image provides socat on port 4004 as a stable proxy that bridges
blocking clients to the non-blocking gateway socket.

Port 4004 is the correct client-facing port for paper mode (4003 for
live). The K8s readiness probe stays on 4002 since TCP probes work
fine with non-blocking sockets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:43:32 +01:00
jgrusewski
d0b896b01c fix(infra): probe TWS API port 4002, use Recreate strategy
Readiness/liveness probes were checking port 4004 (socat), which
always listens even when the gateway is stuck at login — masking
failures. Now probes check port 4002 (TWS API), which only opens
after successful IBKR authentication.

Deploy strategy changed to Recreate because IBKR allows only one
session per account. RollingUpdate starts the new pod before killing
the old one, causing both to fight over the session in a crash loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:37:51 +01:00
jgrusewski
13be624220 fix(infra): add EXISTING_SESSION_DETECTED_ACTION to IB Gateway
The gnzsnz/ib-gateway image renders its IBC config.ini from a template
using envsubst. The ExistingSessionDetectedAction field was rendering
as empty, causing IBC to show a GUI dialog when IBKR detected a
competing session — which nobody could dismiss in a headless pod.

Setting primaryoverride tells IBC to automatically take over any
existing session, which is the correct behavior for a K8s deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:26:10 +01:00
jgrusewski
e0a9dcfb60 Merge branch 'worktree-fxt-broker-check' 2026-03-02 14:02:50 +01:00
jgrusewski
ea130bdb52 chore(fxt): suppress unused_crate_dependencies for ibapi
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:53:02 +01:00
jgrusewski
7dbecf2b64 feat(fxt): wire broker check subcommand into CLI
Add Broker variant to Commands enum with BrokerArgs (flatten),
route to execute_broker_command in match block (no JWT required),
exit(1) on check failure. Clone config.api_gateway_url to avoid
partial move. Add two CLI parsing tests for broker check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:49:43 +01:00
jgrusewski
33208c928c feat(fxt): add broker check command with config resolution and connectivity checks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:44:20 +01:00
jgrusewski
9afd985a34 feat(fxt): compile broker_gateway.proto for gRPC client stubs
Copy broker_gateway.proto from broker_gateway_service into fxt/proto/
and wire it into build.rs compile_protos + lib.rs proto module so the
CLI can call BrokerGatewayService RPCs (health check, account state,
session status).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:37:49 +01:00
jgrusewski
ec23919c97 feat(fxt): add BrokerConfig section to TliConfig
Adds IbkrConfig (host/port/client_id with defaults for paper trading)
and BrokerConfig (gateway_url + ibkr nested) to the TLI config file.
Both structs derive serde defaults so existing config files remain
backward-compatible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:36:35 +01:00
jgrusewski
9e42c9264a feat(fxt): add ibapi optional dep behind broker-check feature
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:33:43 +01:00
jgrusewski
eefb191a62 docs: add implementation plan for fxt broker check command
7 tasks: deps → config → proto → broker.rs → main.rs wiring → lint → verify.
TDD approach with exact file paths and commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:28:51 +01:00
jgrusewski
50d1aff97c docs: add design for fxt broker check CLI command
Two-layer IBKR connectivity validation: direct ibapi handshake +
broker-gateway gRPC health check. Pure-client architecture using
ibapi as optional dep on fxt (not trading_engine).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:26:17 +01:00