feat(broker): add Alpaca paper order draft - #310
Merged
Conversation
Add a local-only Alpaca paper order DRAFT surface. It validates user input and returns a structured draft for human review — it does NOT submit to Alpaca, call any broker, place/cancel/replace any order, execute, or touch the network. - app/schemas/alpaca_paper_order_draft.py — request/draft/response models (extra="forbid"; draft_only=true, order_submission_enabled=false, execution_enabled=false, live_orders_blocked=true, dry_run=true, read_only=true, requires_human_review=true; message "Draft only — not submitted to Alpaca."). - app/services/alpaca_paper_order_draft_service.py — validation + draft builder. Validates side/order_type/time_in_force, exactly-one quantity|notional, required positive stop_loss/take_profit/entry, geometry, and max_risk_pct<=1%. No Alpaca SDK import, no network, no env reads. paper-draft-* ids only. - app/api/routes/alpaca_paper.py — POST /api/alpaca-paper/order-draft (local-only; the only mutating method; clearly documented as not submitted). - tests/app/test_alpaca_paper_order_draft.py — 21 tests (valid/blocked drafts, forbidden-field absence, no-network proof, source has no SDK/submission, route POST 200, GET 405, OpenAPI POST-only draft path). - tests/app/test_safety_invariants.py & test_paper_sandbox_guardrails.py — register the reviewed safe non-execution POST route in the admin allowlists (mirrors the existing /api/paper/tickets/draft precedent). - docs/tasks/alpaca_paper_order_draft_001.md. Does NOT submit orders to Alpaca. No live broker, no credentials, no secrets, no frontend trading controls. Safety posture unchanged: autotrade=false, dry_run=true, read_only=true, live_orders_blocked=true, max risk <= 1%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Melly-999
temporarily deployed
to
feature/alpaca-paper-order-draft-001 - alpha_data_scraper_ai PR #310
June 16, 2026 01:02 — with
Render
Destroyed
Reviewer's GuideAdds a new backend Alpaca paper order draft POST endpoint that validates trade parameters and returns a local-only draft object, plus supporting schema, service, tests, and narrow guardrail/allowlist updates to keep it classified as a non-execution, dry-run-only route. Sequence diagram for the new Alpaca paper order draft POST flowsequenceDiagram
actor Client
participant Router as AlpacaPaperRouter
participant Service as AlpacaPaperOrderDraftService
Client->>Router: POST /api/alpaca-paper/order-draft
Router->>Service: build_alpaca_paper_order_draft(AlpacaPaperOrderDraftRequest)
alt [all validations pass]
Service-->>Router: AlpacaPaperOrderDraftResponse(valid=true, draft=AlpacaPaperOrderDraft)
else [any validation fails]
Service-->>Router: AlpacaPaperOrderDraftResponse(valid=false, draft=None)
end
Router-->>Client: 200 OK (JSON AlpacaPaperOrderDraftResponse)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Melly-999
marked this pull request as ready for review
June 16, 2026 01:33
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The allowed
order_type/time_in_forcevalues are defined both asLiteralaliases inalpaca_paper_order_draft.pyand as_ALLOWED_*frozensets in the service; consider deriving one from the other (or centralizing them) to avoid drift between schema and validation logic. - In
build_alpaca_paper_order_draft,side,order_type, andtime_in_forceare normalized but then passed to the draft model with# type: ignore[arg-type]; you could narrow their types (e.g., via small helper functions or casts after validation) so theAlpacaPaperOrderDraftconstruction is type-safe without ignores.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The allowed `order_type`/`time_in_force` values are defined both as `Literal` aliases in `alpaca_paper_order_draft.py` and as `_ALLOWED_*` frozensets in the service; consider deriving one from the other (or centralizing them) to avoid drift between schema and validation logic.
- In `build_alpaca_paper_order_draft`, `side`, `order_type`, and `time_in_force` are normalized but then passed to the draft model with `# type: ignore[arg-type]`; you could narrow their types (e.g., via small helper functions or casts after validation) so the `AlpacaPaperOrderDraft` construction is type-safe without ignores.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
Backend local draft-only route + schema + service + tests + guardrail allowlist registration + task doc. No frontend, scripts, workflows, package, Docker/Tauri, cloud config, or env files.
bc6f24584ef6e3f6aedea65cb787c55a71aa90c41def558c60907dcd4aa1a324efbc25e0cbe917c1Files changed
app/schemas/alpaca_paper_order_draft.py(new)app/services/alpaca_paper_order_draft_service.py(new)app/api/routes/alpaca_paper.py(modified — new POST route)tests/app/test_alpaca_paper_order_draft.py(new)tests/app/test_safety_invariants.py(modified — admin allowlist)tests/app/test_paper_sandbox_guardrails.py(modified — safe non-execution allowlist)docs/tasks/alpaca_paper_order_draft_001.md(new)Implementation summary
AlpacaPaperOrderDraftRequest/AlpacaPaperOrderDraft/AlpacaPaperOrderDraftResponse(extra="forbid"). Response carriesdraft_only=true,order_submission_enabled=false,execution_enabled=false,live_orders_blocked=true,dry_run=true,read_only=true,requires_human_review=true, message"Draft only — not submitted to Alpaca."build_alpaca_paper_order_draft: validates side / order_type / time_in_force, exactly-one positivequantity|notional, required positiveentry_price/stop_loss/take_profit, BUY/SELL geometry, andmax_risk_pct <= 1.0. No Alpaca SDK import, no network, no env reads. Local deterministicpaper-draft-*ids only (never a broker order id).POST /api/alpaca-paper/order-draft→AlpacaPaperOrderDraftResponse. Validation failures returnvalid=false(HTTP 200), mirroring the existing order-preview pattern.Guardrail changes (narrow, additive only)
test_safety_invariants.py— added("POST", "/api/alpaca-paper/order-draft")toADMIN_NON_GET_ALLOWLISTwith justification (mirrors the existing/api/paper/tickets/draft).test_paper_sandbox_guardrails.py— added the path toSAFE_ADMIN_NON_EXECUTION_PATHSand made guard-2 honor that allowlist exactly like guard-4 already does.Tests / validation summary
max_risk_pct > 1%; all safety flags incl.draft_only/order_submission_enabled=false/execution_enabled=false; no forbidden fields; service makes no network call; source has no SDK/submission references; route POST 200 valid+blocked; GET → 405; OpenAPI POST-only draft path).tests/appsuite: 2415 passed.python scripts/validate_safety_config.py→ OVERALL: PASS.black --check,flake8,mypy(new files) → clean.git diff --check→ clean.Static scan summary
No secrets / token-shaped strings / DB URLs / API keys / broker credentials / account IDs / emails / phones / Neon identifiers. No safety-flip values (the
autotrade=truematches are the pre-existing forbidden-token denylist in the guardrail test). Nofrom alpaca.SDK import and no mutating-order calls (submit_order/place_order/cancel_order/replace_order/TradingClient/MarketOrderRequest/OrderSide) in new code — matches exist only in prohibition comments, denylists, and tests asserting absence.Out of scope
Safety confirmation
🤖 Generated with Claude Code
Summary by Sourcery
Add a local-only Alpaca paper order draft endpoint that validates trade parameters and returns a non-executing draft response while preserving existing broker safety guarantees.
New Features:
Enhancements:
Documentation:
Tests: