syntax = "proto3";

package alt.v1;

option go_package = "git.toki-labs.com/toki/alt/packages/contracts/gen/go/alt/v1;altv1";

import "alt/v1/common.proto";
import "alt/v1/market.proto";
import "alt/v1/backtest.proto";

// paper_trading.proto carries the operator-facing paper trading command/query
// surface. It is kept separate from backtest.proto so a paper account state can
// be started and inspected distinctly from backtest analysis while still reusing
// the shared backtest run/trade/position/equity payload shapes.

message StartPaperTradingRequest {
  string account_id = 1;
  BacktestRunSpec spec = 2;
  Price starting_cash = 3;
}

message StartPaperTradingResponse {
  PaperTradingState state = 1;
  ErrorInfo error = 2;
}

message GetPaperTradingStateRequest {
  string account_id = 1;
}

message GetPaperTradingStateResponse {
  PaperTradingState state = 1;
  ErrorInfo error = 2;
}

message PaperTradingState {
  string account_id = 1;
  BacktestRun run = 2;
  Price cash = 3;
  repeated BacktestPosition positions = 4;
  repeated BacktestTrade fills = 5;
  repeated BacktestEquityPoint equity_curve = 6;
  // risk_rejections lists orders the paper run's risk gate or portfolio refused.
  // It is additive: an empty list means every decided order cleared risk, while a
  // non-empty list lets the operator surface a blocked risk summary without faking
  // broker behaviour. The fill path stays unchanged; this only exposes rejections
  // the engine already tracked internally.
  repeated PaperRiskRejection risk_rejections = 7;
}

// PaperRiskRejection summarises a single order that the paper run did not fill
// because a risk decision or portfolio application denied it. It mirrors the
// worker-owned RejectedOrder so operator surfaces can distinguish clear vs
// blocked risk without inspecting raw engine state.
message PaperRiskRejection {
  string instrument_id = 1;
  string side = 2;
  Quantity quantity = 3;
  string reason = 4;
  int64 timestamp_unix_ms = 5;
}

// PaperOrder is an operator-submitted virtual order tracked against a started
// paper account. Side/type/status stay string-typed to match the existing paper
// summary shapes (PaperRiskRejection.side) and to keep the lifecycle additive
// without introducing new enums. No real broker order is ever created.
message PaperOrder {
  string order_id = 1;
  string account_id = 2;
  string instrument_id = 3;
  // side is "buy" or "sell".
  string side = 4;
  Quantity quantity = 5;
  // type is "market" or "limit".
  string type = 6;
  // limit_price is only set for a limit order.
  Price limit_price = 7;
  // status is "pending", "filled", "canceled", or "rejected".
  string status = 8;
  // reason is populated when status is "rejected" (risk or portfolio denial).
  string reason = 9;
  // fill is populated when status is "filled"; it reuses the BacktestTrade shape
  // so a fill summary carries instrument/side/quantity/price/timestamp.
  BacktestTrade fill = 10;
  int64 created_at_unix_ms = 11;
  int64 updated_at_unix_ms = 12;
}

message SubmitPaperOrderRequest {
  string account_id = 1;
  string instrument_id = 2;
  string side = 3;
  Quantity quantity = 4;
  string type = 5;
  Price limit_price = 6;
}

message SubmitPaperOrderResponse {
  PaperOrder order = 1;
  ErrorInfo error = 2;
}

message CancelPaperOrderRequest {
  string account_id = 1;
  string order_id = 2;
}

message CancelPaperOrderResponse {
  PaperOrder order = 1;
  ErrorInfo error = 2;
}

message FillPaperOrderRequest {
  string account_id = 1;
  string order_id = 2;
  // fill_price is the simulated execution price for a market order. A limit order
  // executes at its own limit price, so fill_price may be omitted for it.
  Price fill_price = 3;
}

message FillPaperOrderResponse {
  PaperOrder order = 1;
  // state is the account snapshot after the fill so the operator sees the cash
  // and position effect without a second query. For a rejected order it carries
  // the unchanged account state.
  PaperTradingState state = 2;
  ErrorInfo error = 3;
}
