Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bobby Copy Agent

Customer-side copy trading execution agent.

This repo is intentionally small. It does not contain alpha logic, trading-system database schemas, portfolio engines, or internal risk engines. It contains only the public-safe contracts and runtime pieces needed by a customer VPS agent:

  • copy.event.v1 normalization.
  • copy.command.v1 execution command builders.
  • local idempotency.
  • local guardrails.
  • data_layer REST client for warmup/recovery/freshness checks.
  • dry-run broker execution.
  • Binance USDM request mapping.
  • CLI diagnostics.
  • SaaS command polling over outbound HTTPS.
  • command signature verification.
  • AI/operator support workflow in AGENT_SKILL.md.

Install

Development install:

pip install -e .

Docker smoke:

docker build -f docker/Dockerfile -t bobby-copy-agent:local .
docker run --rm bobby-copy-agent:local copy-agent doctor --agent-id demo-agent

CLI

Doctor:

copy-agent doctor --agent-id demo-agent --verbose

Doctor with config:

copy-agent doctor --config examples/agent_config.example.json --verbose

Dry-run one command:

copy-agent dry-run-command examples/place_order_command.json \
  --adapter dry-run \
  --allowed-symbol ETHUSDT \
  --allowed-venue BINANCE \
  --max-notional 100

Map to Binance USDM request without submitting:

copy-agent dry-run-command examples/place_order_command.json \
  --adapter binance-usdm \
  --allowed-symbol ETHUSDT \
  --allowed-venue BINANCE

Sign a local fixture command for smoke testing:

copy-agent sign-command examples/place_order_command.json \
  --hmac-secret local-fixture-secret

Verify a signed command:

copy-agent verify-command signed_command.json \
  --hmac-secret local-fixture-secret

Poll one batch from the SaaS command API and report results:

copy-agent run-once \
  --config examples/agent_config.example.json

Run continuously:

copy-agent run \
  --config examples/agent_config.example.json

Send one heartbeat:

copy-agent heartbeat \
  --config examples/agent_config.example.json

Diagnose a log file:

copy-agent diagnose-log ~/.copy_agent/agent.log --tail-lines 500

Check data_layer contract:

copy-agent data-layer-check \
  --base-url http://data_layer:8100 \
  --symbol BTCUSDT \
  --market crypto \
  --provider binance \
  --binance-market usdm \
  --interval 15m \
  --limit 5

Production Shape

The customer agent should connect outbound to the SaaS server by HTTPS polling or WebSocket. Redis stream access is private-lab only and should not be exposed to customer VPS.

The SaaS server should:

  1. Consume copy.event.v1 from trading-system.
  2. Apply investor subscription sizing and risk.
  3. Emit signed copy.command.v1 commands to the customer agent.
  4. Store result reports from the agent.

The customer agent should:

  1. Verify signature and expiry.
  2. Deduplicate by copy_command_id / idempotency_key.
  3. Apply local guardrails.
  4. Execute through the customer's broker credentials.
  5. Report broker result back to SaaS.

SaaS Command Polling

The production transport is outbound HTTPS from the customer VPS to the SaaS server. The default contract is:

  • GET /api/agent/v1/commands?agent_id=...&limit=...
  • POST /api/agent/v1/results
  • POST /api/agent/v1/heartbeat

GET /commands may return either:

{"commands": []}

or a direct JSON array:

[]

Authentication is separate from command signing. The agent sends a programmatic client API key to the SaaS server. A typical key is generated by the SaaS client portal with an lk_live_... prefix, shown to the investor once, and stored server-side only as a SHA-256 hash. The agent stores the raw key locally because it must authenticate future outbound requests.

Default header:

Authorization: Bearer lk_live_...

Alternative X-API-Key style:

COPY_AGENT_AUTH_HEADER=X-API-Key
COPY_AGENT_AUTH_SCHEME=

Core env vars:

COPY_AGENT_ID=customer-vps-agent-001
COPY_AGENT_SAAS_BASE_URL=https://copy-api.example.com
COPY_AGENT_API_KEY=lk_live_replace_with_key_shown_once
COPY_AGENT_REQUIRE_SAAS_AUTH=true
COPY_AGENT_STATE_PATH=~/.copy_agent/idempotency.json
COPY_AGENT_ADAPTER=dry-run
COPY_AGENT_BROKER_MODE=dry-run
COPY_AGENT_LIVE_SUBMIT=false
COPY_AGENT_POLL_LIMIT=10
COPY_AGENT_POLL_INTERVAL_SECONDS=2
COPY_AGENT_REQUIRE_SIGNATURE=true
COPY_AGENT_HMAC_SECRET=replace_with_command_signature_secret
COPY_AGENT_ALLOWED_SYMBOLS=BTCUSDT,ETHUSDT
COPY_AGENT_ALLOWED_VENUES=BINANCE
COPY_AGENT_MAX_NOTIONAL=100
COPY_AGENT_CAPITAL=1000
COPY_AGENT_ALLOCATION_PCT=0.1
COPY_AGENT_LEVERAGE=1
COPY_AGENT_QUANTITY_MULTIPLIER=1
COPY_AGENT_MARGIN_MODE=ISOLATED

Local Investor Policy

The SaaS server should already transform source trading-system events into investor-specific, sized copy.command.v1 commands. The customer agent still applies a final local policy before the broker call:

  • COPY_AGENT_CAPITAL
  • COPY_AGENT_ALLOCATION_PCT
  • COPY_AGENT_LEVERAGE
  • COPY_AGENT_MAX_NOTIONAL
  • COPY_AGENT_MAX_QUANTITY
  • COPY_AGENT_QUANTITY_MULTIPLIER
  • COPY_AGENT_MARGIN_MODE

This local policy is an extra safety overlay, not a replacement for SaaS-side subscription sizing. It can scale quantities and cap command max_notional. It does not fabricate prices for MARKET orders; if a strategy needs strict notional control, SaaS should send a reference price or a limit order and the agent should keep COPY_AGENT_MAX_NOTIONAL conservative.

Signature Verification

The API key authenticates the agent to the SaaS API. The command signature protects each command payload from tampering or replay. Do not reuse the API key as the command signing secret.

First release signature algorithm:

  • signature_algorithm=hmac-sha256
  • canonical payload excludes signature and signature_algorithm
  • JSON is sorted and compact before signing
  • digest is URL-safe base64 without padding

When COPY_AGENT_REQUIRE_SIGNATURE=true, the agent rejects a command before broker execution if:

  • signature_algorithm is missing or unsupported;
  • signature is missing;
  • COPY_AGENT_HMAC_SECRET is missing;
  • payload verification fails;
  • command expiry fails local guard validation.

The HMAC path is intentionally simple for the first release. A future Ed25519 mode can be added without changing the command transport shape: SaaS signs with a private key and the public agent verifies with a public verify key.

Binance USDM Testnet

The agent includes a small direct Binance USD-M Futures REST client so testnet/live submission does not depend on python-binance.

Required env for testnet:

COPY_AGENT_ADAPTER=binance-usdm
COPY_AGENT_BROKER_MODE=testnet
COPY_AGENT_LIVE_SUBMIT=true
COPY_AGENT_BINANCE_API_KEY=...
COPY_AGENT_BINANCE_API_SECRET=...
COPY_AGENT_ALLOWED_SYMBOLS=BTCUSDT,ETHUSDT
COPY_AGENT_MAX_NOTIONAL=25
COPY_AGENT_REQUIRE_SIGNATURE=true
COPY_AGENT_HMAC_SECRET=...

Connectivity/account check:

copy-agent test-broker \
  --config examples/agent_config.example.json \
  --broker binance-usdm \
  --testnet \
  --query-account

Place and immediately cancel a tiny far-from-market LIMIT order:

copy-agent test-broker \
  --config examples/agent_config.example.json \
  --broker binance-usdm \
  --testnet \
  --place-cancel-smoke \
  --confirm TESTNET_ORDER \
  --symbol BTCUSDT \
  --quantity 0.001 \
  --price 1

Automated smoke tests should use LIMIT orders far from market by default. Do not use MARKET orders for automated broker smoke unless a human explicitly approves that specific run.

Live Broker Submission

Live is blocked by default. To enable live Binance USDM, all of these must be true:

  • COPY_AGENT_ADAPTER=binance-usdm
  • COPY_AGENT_BROKER_MODE=live
  • COPY_AGENT_LIVE_SUBMIT=true
  • COPY_AGENT_LIVE_CONFIRM=I_UNDERSTAND_THIS_SUBMITS_LIVE_ORDERS
  • COPY_AGENT_REQUIRE_SIGNATURE=true
  • COPY_AGENT_ALLOWED_SYMBOLS is non-empty
  • COPY_AGENT_MAX_NOTIONAL is set
  • Binance API key/secret are present
  • local HALT file does not exist

Preflight:

copy-agent live-preflight \
  --config examples/agent_config.example.json

Preflight with broker account/open-order check:

copy-agent live-preflight \
  --config examples/agent_config.example.json \
  --check-broker

Emergency halt:

mkdir -p ~/.copy_agent
touch ~/.copy_agent/HALT

When the halt file exists, the agent rejects new commands before broker execution. Remove it only after the operator understands the current broker state.

Customer Service / Security Notes

  • A technician should never ask for or store customer broker secrets outside the customer's VPS.
  • Prefer screen share or guided terminal commands where the customer enters credentials locally.
  • Use testnet/sandbox first, then a tiny live smoke only after explicit customer approval.
  • Do not grant withdrawal permission to exchange API keys.
  • Start with symbol allowlists and low notional caps.
  • Keep logs useful but redact API keys, secrets, signatures, and raw account identifiers where possible.
  • SaaS API keys (lk_live_...) should be revocable from the client portal and stored server-side only as SHA-256 hashes.
  • Command signing secrets/public keys should be rotated separately from API keys.

Data Layer Contract

The agent uses the same market-data integration standard as the rest of the Bobby stack:

  • REST for warmup, latest-state recovery, diagnostics, and freshness checks.
  • Redis Pub/Sub only as an optional/private-lab streaming transport.
  • No direct Binance/DNSE/vnstock/OKX market-data connections when running inside the stack.

Client module:

from copy_agent.data_layer import DataLayerClient

client = DataLayerClient(base_url="http://data_layer:8100")
health = client.health()
warmup = client.warmup_ohlcv("crypto", "BTCUSDT", interval="15m", limit=500, provider="binance")
latest = client.latest_trade("binance", "BTCUSDT", market="usdm", allow_last_snapshot=True)
freshness = client.validate_freshness(latest, max_age_seconds=5)

VN example:

warmup = client.warmup_ohlcv("vn_stock", "FPT", interval="15m", limit=500)
quote = client.latest_vn_quote("FPT", allow_last_snapshot=True)

Safety Defaults

  • Dry-run is the default.
  • Binance adapter does not submit unless constructed with live_submit=True.
  • DNSE adapter is a stub until endpoint semantics are confirmed.
  • Local idempotency persists to ~/.copy_agent/idempotency.json by default.
  • Result-report failure does not replay broker execution; the local idempotency key remains marked.

AI / Operator Skill

AGENT_SKILL.md is the short operational playbook for an AI support agent or technician. It covers:

  • safe setup rules;
  • doctor/diagnose commands;
  • Binance testnet smoke;
  • live preflight;
  • emergency HALT file;
  • common error meanings without exposing secrets.