﻿# Paper Order Management — Legacy v1 (REMOVED)

> **Status:** Removed from the live codebase. This document archives the endpoints,
> request/response shapes, and business logic that lived in
> `App\Http\Controllers\PaperOrderManagementController` so the design can still be
> referenced. Do **not** re-add these routes without an explicit product decision.
>
> **Removed on:** 2026-08-06  
> **Replaced by:** Paper Order MS v2 — see [`paperOrderMS.md`](paperOrderMS.md)  
> (`PaperOrderPlacerController`, `PaperOrderExecuterController`,
> `PaperOrderModifierController`, `PaperOrderInfoController`,
> `PaperMarketDepthOrderbookManagementController`).

---

## Why it was removed

1. **Two execution engines collided.** v1 auto-executed any pending order older than
   ~50 seconds as a side effect of `order-status` / `portfolio` / `modify` / `cancel` /
   `order-log`. v2 uses an explicit matching engine (`execute-queue`). Calling a v1
   poll endpoint after a v2 partial fill could **double-fill** the outstanding qty
   (fixed shortly before removal in `PaperOrderLegacyExecutionOverfillTest`, then
   retired with this controller).
2. **No real matching.** v1 filled the full remaining qty at requested (limit) or LTP
   (market) once “due” — it did not walk an order book or match client-to-client.
3. **No immature / bridge-loan path.** Sell proceeds were credited straight to
   `cash_balance`; v2 schedules immature proceeds via `PaperBalanceService`.
4. **API surface duplicated.** Place/modify/cancel/status/depth/portfolio all had
   v2 equivalents (or partial replacements such as sellable-shares + purchasing-power).

---

## Removed route index

| Action | Method | Route name | URL | v2 replacement |
|--------|--------|------------|-----|----------------|
| Market depth (simulated) | `GET\|POST` | `paper-order-market-depth` | `/api/paper-order/market-depth` | `/api/paper-order/market-depth-v2` |
| Place buy/sell | `POST` | `paper-order-place-order` | `/api/paper-order/place-order` | `/api/paper-order/order-place` |
| Modify pending | `POST` | `paper-order-modify-order` | `/api/paper-order/modify-order` | `/api/paper-order/order-modify` |
| Cancel pending | `POST` | `paper-order-cancel-order` | `/api/paper-order/cancel-order` | `/api/paper-order/order-cancel` (+ `cancel-all`) |
| Order status (also auto-executes due) | `GET\|POST` | `paper-order-order-status` | `/api/paper-order/order-status` | `/api/paper-order/order-detail` *(read-only)* |
| Client portfolio (also auto-executes due) | `GET\|POST` | `paper-order-portfolio` | `/api/paper-order/portfolio` | **v2 restored:** same path via `PaperOrderInfoController::portfolio` — **no** auto-exec; adds immature/bridge balances + pending-sell-aware sellable |
| Order log *(date-grouped, v1 handler)* | `GET\|POST` | — | `/api/paper-order/order-log` *(old handler)* | Same URL, now `PaperOrderInfoController::orderLog` (flat/paginated; **no** auto-execution) |

**Deleted file:** `app/Http/Controllers/PaperOrderManagementController.php`

---

## Constants & shared rules (controller)

| Constant | Value | Meaning |
|----------|-------|---------|
| `MIN_EXECUTION_DELAY` | 10 s | Lower bound of random auto-exec delay after place/modify *(historical; delay was later driven by `order_datetime + MAX` poll)* |
| `MAX_EXECUTION_DELAY` | 50 s | Order is “due” when `order_datetime <= now() - 50s` |
| `ORDER_TYPES` | `market`, `spot`, `parking`, `limit` | Accepted order types |
| `CATEGORY_SETTLEMENT_DAYS` | A/B → 1, Z → 2, S → 0 | Business days; Fri/Sat skipped; `spot` forces T+0 |
| Snapshot cache | `todays_mkt_latest_snapshot`, TTL 15 s | Same key as `TodaysMktDataController::latestSnapshot()` |

### Price band (±10% of opening)

At place and modify: `requested_price` must lie in `[0.9 × open, 1.1 × open]`.  
Open fallback: `OPEN_PRICE` → else `YDAY_CLOSE_PRICE` → else current market price.

### Sellable quantity

```
sellable = holding.quantity − unsettled_buy_qty − other_pending_sell_remaining_qty
```

Unsettled buys = `paper_share_holding_log` side `B` with `settlement_date > today`.

---

## Auto-execution engine (core business logic)

**Trigger:** `executeDuePendingOrders($paperboId)` — called from v1
`placeOrder` (not always), **`modifyOrder`**, **`cancelOrder`**, **`orderStatus`**,
**`orderLog`**, **`portfolio`**.

**Selection:**

```
pending orders for paperbo_id
WHERE order_datetime <= now() - 50 seconds
ORDER BY order_datetime ASC
```

**Per order (`executeOrder`) — final version before removal:**

1. Lock order; bail if not still `pending`.
2. `alreadyFilled = SUM(paper_exe_log.executed_qty)`; `remaining = requested_qty − alreadyFilled`.
3. If `remaining <= 0` → roll header from all exe rows to `executed` / `FILL` (idempotent).
4. Resolve execution price: limit/parking → `requested_price`; market/spot → LTP (or fetched).
5. Reject (or leave PF if already partially filled) if no price or price outside day high/low.
6. Fill **only** `remaining` qty (not full `requested_qty`) — buy/sell paths below.
7. Write `paper_exe_log`, holdings (+log), wallet trade + commission, update `paper_bo`, roll order header from **all** fills.

### Buy (`executeBuy`)

- Cost check: `cash_balance >= gross + commission` (full remaining fill only — no immature PP).
- Upsert `paper_share_holding` (avg cost weighted).
- Insert `paper_share_holding_log` (side B).
- Wallet: `buy` DR + `commission` DR; debit `cash_balance`; add to `invested_value`.
- **Did not** call `PaperBalanceService::consumeForBuy` (no immature consumption).

### Sell (`executeSell`)

- Require `sellableQuantity >= quantity`.
- Reduce holding; log realized PnL on holding log.
- Wallet: `sell` CR + `commission` DR; **credit net proceeds immediately to `cash_balance`**.
- **Did not** create `paper_schedule_wallet_log` or bump `bridge_loan_available_balance` /
  `purchaseable_immature_balance`.

### Reject

- Sets `status=rejected`, `execution_type=REJ`, `rejection_reason`, `executed_at`.
- Partial fills: later harden used `rejectOrRollUp` so a PF order was not flipped to rejected.

### Day high/low guard (execution)

Execution price must be inside snapshot `LOW_PRICE`–`HIGH_PRICE` (inclusive); otherwise reject / skip.

---

## Endpoint catalogue (archived from paper_bo.md §16–§22)

The following sections are the historical API docs for the removed endpoints.
## 16. Market depth (simulated order book + fundamentals)

Returns the current market snapshot, simulated buy/sell depth, and fundamentals (EPS, P/E ratio) for one security. Price data comes from the same snapshot cache as `api/todays-data/instrument-snapshot`; EPS comes from the latest-year row in `mkt_security_matric_data` (same source as `api/mkt-security-matric-data/by-security-code`). P/E ratio is computed as market price Ã· EPS (null when EPS is missing or â‰¤ 0).

| Item | Value |
|------|-------|
| **Method** | `GET` or `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/market-depth` |
| **Params** | `security_code` (required) |

**Depth rules**
- Market price = `LAST_TRADED_PRICE`; falls back to `YDAY_CLOSE_PRICE` when LTP is null/zero.
- Price step = `0.10` per `2.00` of the high-low range; minimum `0.10`, maximum `1.50`.
- Buy prices are below market price and never below `LOW_PRICE`.
- Sell prices are above market price and never above `HIGH_PRICE`.
- Up to 20 generated rows per side, each with a random quantity from 10â€“5,000.
- If market price equals the day's low/high, that side can contain fewer than 20 valid rows.

### cURL

```bash
curl --location '{{BASE_URL}}/api/paper-order/market-depth?security_code={{SECURITY_CODE}}' \
--header 'Accept: application/json'
```

### Success response (200)

```json
{
  "status": true,
  "message": "Market depth fetched successfully",
  "last_updated": "2026-07-18 20:25:00",
  "data": {
    "security_code": "IFIC",
    "security_name": "IFIC Bank PLC",
    "sector": "Bank",
    "market_price": "5.00",
    "LTP": "5.00",
    "LAST_TRADED_PRICE": "5.00",
    "YDAY_CLOSE_PRICE": "5.00",
    "OPEN_PRICE": "5.10",
    "HIGH_PRICE": "5.10",
    "LOW_PRICE": "4.90",
    "CHANGE_YDAY_CLOSE": "0.00",
    "CHANGE_PCT_YDAY_CLOSE": "0.00",
    "TOTAL_TRADES": 209,
    "TOTAL_VOLUME": 1408347,
    "TOTAL_VALUE": "7.044000",
    "EPS": 0.45,
    "PE_RATIO": 11.11,
    "eps_year": 2025,
    "sentiment": {
      "buy": [
        { "quantity": 234, "price": "4.90" }
      ],
      "sell": [
        { "quantity": 765, "price": "5.10" }
      ]
    }
  }
}
```

---

## 17. Place buy/sell order

Validates the active paper BO, security, cash or settled holdings, then creates a pending order with a random execution delay of 10â€“50 seconds.

| Item | Value |
|------|-------|
| **Method** | `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/place-order` |

### Body

| Field | Required | Notes |
|-------|----------|-------|
| `paperbo_id` | yes | Active paper BO account |
| `security_code` | yes | Active `mkt_security_code.security_code` |
| `side` | yes | `B` (buy) or `S` (sell) |
| `quantity` | yes | Integer â‰¥ 1 |
| `order_type` | yes | `market`, `spot`, `parking`, `limit` |
| `price` | yes | Buy/sell price for every order type; must stay within Â±10% of the opening price |
| `device_id` | no | Client device identifier, max 100 in DB |

### Price band rule (Â±10% of opening price)

The requested `price` (buy or sell) may never go more than **10% above or below the day's opening price**. When `OPEN_PRICE` is unavailable (zero/null), yesterday's close is used, then the current market price.

Violations return **422**:

```json
{
  "status": false,
  "message": "Requested price is outside the allowed 10% band of the opening price.",
  "opening_price": "5.10",
  "min_allowed_price": "4.59",
  "max_allowed_price": "5.61",
  "requested_price": "6.00"
}
```

### Execution-price behavior

| Order type | Execution price |
|------------|-----------------|
| `market` | Current market price at execution |
| `spot` | Current market price at execution; T+0 settlement |
| `limit` | Requested `price` |
| `parking` | Requested `price` |

> Market/spot orders still execute at the live market price; the body `price` is validated against the 10% band and stored as `requested_price`. Limit/parking execute at the requested price once due; the engine does not yet test whether the live market crossed that price.

### Settlement

| Security category | Settlement |
|-------------------|------------|
| `A`, `B` | T+1 |
| `Z` | T+2 |
| `S` | T+0 |
| Missing/other | T+1 |
| Any `spot` order | T+0 |

Friday and Saturday are skipped when calculating T+1/T+2.

### cURL â€” market buy

```bash
curl --location '{{BASE_URL}}/api/paper-order/place-order' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
  "paperbo_id": {{PAPER_BO_ID}},
  "security_code": "{{SECURITY_CODE}}",
  "side": "B",
  "quantity": 100,
  "order_type": "market",
  "price": 5.00,
  "device_id": "web-browser"
}'
```

### cURL â€” limit sell

```bash
curl --location '{{BASE_URL}}/api/paper-order/place-order' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
  "paperbo_id": {{PAPER_BO_ID}},
  "security_code": "{{SECURITY_CODE}}",
  "side": "S",
  "quantity": 50,
  "order_type": "limit",
  "price": 5.20
}'
```

### Success response (201)

```json
{
  "status": true,
  "message": "Order placed successfully. It will be executed automatically.",
  "data": {
    "order_no": "ORD-2026-000001",
    "paperbo_id": 1,
    "security_code": "IFIC",
    "security_category": "A",
    "settlement_date": "2026-07-19",
    "side": "B",
    "order_type": "market",
    "quantity": 100,
    "requested_price": "5.0000",
    "market_price_at_order": "5.00",
    "order_status": "pending",
    "order_datetime": "2026-07-18 21:10:00",
    "scheduled_execution_at": "2026-07-18 21:10:32"
  }
}
```

### Business errors (422)

- Paper BO account is not active.
- No market price is available.
- Insufficient cash for a buy (gross value + estimated commission).
- Insufficient settled/sellable shares for a sell.
- Pending sell orders reserve quantity and prevent double-selling.

---

## 18. Modify pending order

Modifies a still-pending order's `quantity`, `price` and/or `order_type`. Side and security cannot be changed â€” [cancel the order](#19-cancel-pending-order) and place a new one for those. All placement checks are re-run (10% price band against the opening price, cash for buys, sellable shares for sells) and the auto-execution is rescheduled 10â€“50 seconds ahead.

> If the order's scheduled execution time has already passed, it executes on this request and the modification is rejected with `Only pending orders can be modified.`

| Item | Value |
|------|-------|
| **Method** | `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/modify-order` |

### Body

| Field | Required | Notes |
|-------|----------|-------|
| `order_no` | yes | Order number returned by place-order |
| `quantity` | optional | New quantity, integer â‰¥ 1 |
| `price` | optional | New price; must stay within Â±10% of the opening price |
| `order_type` | optional | `market`, `spot`, `parking`, `limit`; settlement date is recalculated |

At least one of `quantity`, `price`, `order_type` must be provided.

### cURL

```bash
curl --location '{{BASE_URL}}/api/paper-order/modify-order' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
  "order_no": "{{ORDER_NO}}",
  "quantity": 150,
  "price": 5.10
}'
```

### Success response (200)

```json
{
  "status": true,
  "message": "Order modified successfully. Execution rescheduled.",
  "data": {
    "order_no": "ORD-2026-000001",
    "paperbo_id": 1,
    "security_code": "IFIC",
    "security_category": "A",
    "settlement_date": "2026-07-20",
    "side": "B",
    "order_type": "market",
    "quantity": 150,
    "requested_price": "5.1000",
    "order_status": "pending",
    "order_datetime": "2026-07-18 21:10:00",
    "scheduled_execution_at": "2026-07-18 21:12:45",
    "seconds_until_execution": 34
  }
}
```

### Business errors (422)

- `Only pending orders can be modified.` â€” order already executed/rejected (including lazy execution triggered by this request).
- `Nothing to modify. Provide at least one of: quantity, price, order_type.`
- `Requested price is outside the allowed 10% band of the opening price.`
- Insufficient cash for the modified buy order.
- Insufficient sellable shares for the modified sell order (this order's own pending reservation is excluded from the check).

Every modification is appended to the order's `validation_snapshot.modifications` array with old/new values and the market price at modify time, so the full change history is auditable.

---

## 19. Cancel pending order

Cancels a still-pending order. Since nothing is booked in cash or holdings until an order actually executes, cancelling has **no wallet or portfolio impact** â€” it simply flips `status` to `cancelled` so the order never auto-executes.

> If the order's scheduled execution time has already passed, it executes on this request (lazy execution runs first) and the cancel is rejected with `Only pending orders can be cancelled.`

| Item | Value |
|------|-------|
| **Method** | `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/cancel-order` |

### Body

| Field | Required | Notes |
|-------|----------|-------|
| `order_no` | yes | Order number returned by place-order |
| `reason` | no | Free-text cancellation reason; stored in `rejection_reason`. Defaults to `Cancelled by client request` |

### cURL

```bash
curl --location '{{BASE_URL}}/api/paper-order/cancel-order' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
  "order_no": "{{ORDER_NO}}",
  "reason": "Changed my mind"
}'
```

### Success response (200)

```json
{
  "status": true,
  "message": "Order cancelled successfully.",
  "data": {
    "order_no": "ORD-2026-000002",
    "paperbo_id": 1,
    "security_code": "IFIC",
    "security_category": "A",
    "settlement_date": "2026-07-22",
    "side": "B",
    "order_type": "limit",
    "order_status": "cancelled",
    "requested_qty": 10,
    "requested_price": "5.0000",
    "executed_qty": null,
    "executed_price": null,
    "gross_value": null,
    "commission_amount": null,
    "net_value": null,
    "charges_breakdown": null,
    "rejection_reason": "Changed my mind",
    "order_datetime": "2026-07-21 15:26:22",
    "scheduled_execution_at": "2026-07-21 15:36:22",
    "executed_at": null
  }
}
```

### Business errors (422)

- `Only pending orders can be cancelled.` â€” order already `executed`, `rejected`, or `cancelled` (the response includes the current `order_status`).

---

## 20. Order status and execution confirmation

Poll this endpoint using the `order_no` returned by order placement.

| Item | Value |
|------|-------|
| **Method** | `GET` or `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/order-status` |
| **Params** | `order_no` (required) |

### Important execution behavior

The 10â€“50 second execution is **lazy/poll-driven**. There is no background queue worker in this implementation. A due order is executed when either:
- the order-status endpoint is requested, or
- the portfolio endpoint is requested.

The frontend should poll this endpoint until `order_status` becomes `executed` or `rejected`.

### cURL

```bash
curl --location '{{BASE_URL}}/api/paper-order/order-status?order_no={{ORDER_NO}}' \
--header 'Accept: application/json'
```

### Pending response (200)

```json
{
  "status": true,
  "message": "Order is pending execution.",
  "data": {
    "order_no": "ORD-2026-000001",
    "paperbo_id": 1,
    "security_code": "IFIC",
    "security_category": "A",
    "settlement_date": "2026-07-19",
    "side": "B",
    "order_type": "market",
    "order_status": "pending",
    "requested_qty": 100,
    "requested_price": "5.0000",
    "executed_qty": null,
    "executed_price": null,
    "gross_value": null,
    "commission_amount": null,
    "net_value": null,
    "charges_breakdown": null,
    "rejection_reason": null,
    "order_datetime": "2026-07-18 21:10:00",
    "scheduled_execution_at": "2026-07-18 21:10:32",
    "executed_at": null,
    "seconds_until_execution": 20
  }
}
```

### Executed confirmation (200)

```json
{
  "status": true,
  "message": "Order executed successfully.",
  "data": {
    "order_no": "ORD-2026-000001",
    "paperbo_id": 1,
    "security_code": "IFIC",
    "security_category": "A",
    "settlement_date": "2026-07-19",
    "side": "B",
    "order_type": "market",
    "order_status": "executed",
    "requested_qty": 100,
    "requested_price": "5.0000",
    "executed_qty": 100,
    "executed_price": "5.0000",
    "gross_value": "500.00",
    "commission_amount": "2.25",
    "net_value": "502.25",
    "charges_breakdown": {
      "commission_pct": "0.450",
      "commission_amount": "2.25"
    },
    "rejection_reason": null,
    "executed_at": "2026-07-18 21:10:33",
    "seconds_until_execution": 0
  }
}
```

Execution creates/updates:
- `paper_share_holding`
- `paper_share_holding_log`
- `paper_wallet` trade and commission entries
- `paper_bo` cash/invested value/PnL
- `paper_order_log` execution values and related IDs

---

## 21. Client portfolio

Executes due orders first, refreshes current prices, and returns account totals, holdings, settlement-wise sellable quantity, and pending orders.

| Item | Value |
|------|-------|
| **Method** | `GET` or `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/portfolio` |
| **Params** | `paperbo_id` (required) |

### Sellable quantity

`sellable_quantity = holding quantity âˆ’ unsettled buy quantity âˆ’ pending sell quantity`

Unsettled purchases are grouped by `settlement_date`.

### cURL

```bash
curl --location '{{BASE_URL}}/api/paper-order/portfolio?paperbo_id={{PAPER_BO_ID}}' \
--header 'Accept: application/json'
```

### Success response (200)

```json
{
  "status": true,
  "message": "Portfolio fetched successfully",
  "data": {
    "paperbo_id": 1,
    "type": "normal",
    "campaign_id": null,
    "cash_balance": "99347.75",
    "invested_value": "502.25",
    "total_market_value": "500.00",
    "total_equity": "99847.75",
    "realized_pnl": "0.00",
    "unrealized_pnl": "-2.25",
    "total_return_pct": "-0.1523",
    "holdings": [
      {
        "security_code": "IFIC",
        "quantity": 100,
        "sellable_quantity": 0,
        "unsettled_quantity": 100,
        "unsettled_by_date": [
          {
            "settlement_date": "2026-07-19",
            "quantity": 100
          }
        ],
        "avg_cost": "5.0225",
        "total_cost": "502.25",
        "current_price": "5.0000",
        "market_value": "500.00",
        "unrealized_pnl": "-2.25",
        "unrealized_pnl_pct": "-0.4479"
      }
    ],
    "pending_orders": []
  }
}
```

---

## 22. Order log (date wise)

All orders of a paper BO account grouped by order date, newest date first. Any due pending orders are executed before the log is built, so statuses are always current.

| Item | Value |
|------|-------|
| **Method** | `GET` or `POST` |
| **URL** | `{{BASE_URL}}/api/paper-order/order-log` |
| **Params** | `paperbo_id` (required), `from_date` + `to_date` (optional pair, `Y-m-d`) |

### cURL â€” all orders

```bash
curl --location '{{BASE_URL}}/api/paper-order/order-log?paperbo_id={{PAPER_BO_ID}}' \
--header 'Accept: application/json'
```

### cURL â€” date range

```bash
curl --location '{{BASE_URL}}/api/paper-order/order-log?paperbo_id={{PAPER_BO_ID}}&from_date=2026-07-01&to_date=2026-07-19' \
--header 'Accept: application/json'
```

### Success response (200)

```json
{
  "status": true,
  "message": "Order log fetched successfully",
  "data": {
    "paperbo_id": 1,
    "campaign_id": null,
    "filter": {
      "from_date": null,
      "to_date": null
    },
    "summary": {
      "total_orders": 3,
      "pending": 1,
      "executed": 2,
      "rejected": 0,
      "cancelled": 0,
      "buy_orders": 2,
      "sell_orders": 1
    },
    "order_log": [
      {
        "date": "2026-07-19",
        "order_count": 2,
        "orders": [
          {
            "order_no": "ORD-2026-000003",
            "paperbo_id": 1,
            "security_code": "IFIC",
            "security_category": "A",
            "settlement_date": "2026-07-20",
            "side": "S",
            "order_type": "limit",
            "order_status": "pending",
            "requested_qty": 50,
            "requested_price": "5.2000",
            "executed_qty": null,
            "executed_price": null,
            "gross_value": null,
            "commission_amount": null,
            "net_value": null,
            "charges_breakdown": null,
            "rejection_reason": null,
            "order_datetime": "2026-07-19 13:05:12",
            "scheduled_execution_at": "2026-07-19 13:05:47",
            "executed_at": null
          },
          {
            "order_no": "ORD-2026-000002",
            "paperbo_id": 1,
            "security_code": "IFIC",
            "security_category": "A",
            "settlement_date": "2026-07-20",
            "side": "B",
            "order_type": "market",
            "order_status": "executed",
            "requested_qty": 100,
            "requested_price": "5.0000",
            "executed_qty": 100,
            "executed_price": "5.0000",
            "gross_value": "500.00",
            "commission_amount": "2.25",
            "net_value": "502.25",
            "charges_breakdown": {
              "commission_pct": "0.450",
              "commission_amount": "2.25"
            },
            "rejection_reason": null,
            "order_datetime": "2026-07-19 12:58:03",
            "scheduled_execution_at": "2026-07-19 12:58:31",
            "executed_at": "2026-07-19 12:58:40"
          }
        ]
      },
      {
        "date": "2026-07-18",
        "order_count": 1,
        "orders": [
          {
            "order_no": "ORD-2026-000001",
            "order_status": "executed",
            "side": "B",
            "security_code": "GP",
            "requested_qty": 20,
            "requested_price": "310.0000",
            "executed_price": "310.1000",
            "order_datetime": "2026-07-18 21:10:00"
          }
        ]
      }
    ]
  }
}
```

> Orders inside each date group are sorted newest first. The date range filter uses `order_datetime` in Asia/Dhaka time; both `from_date` and `to_date` must be sent together.

---

---

## Migration cheat sheet (client)

| Old call | New call |
|----------|----------|
| `POST /api/paper-order/place-order` | `POST /api/paper-order/order-place` then `POST\|GET /api/paper-order/execute-queue` |
| `POST /api/paper-order/modify-order` | `POST /api/paper-order/order-modify` (CARM) |
| `POST /api/paper-order/cancel-order` | `POST /api/paper-order/order-cancel` |
| `GET /api/paper-order/order-status?order_no=` | `GET /api/paper-order/order-detail?order_no=` *(no side-effect execution)* |
| `GET /api/paper-order/market-depth?security_code=` | `GET\|POST /api/paper-order/market-depth-v2` |
| `GET /api/paper-order/portfolio?paperbo_id=` | Same path → v2 `PaperOrderInfoController::portfolio` (no auto-exec; see `paperOrderMS.md` §6.3) |
| `GET /api/paper-order/order-log` (date buckets) | Same path → v2 paginated flat list (`PaperOrderInfoController`) |

---

## Related live docs

- [`paperOrderMS.md`](paperOrderMS.md) — current Paper Order MS (v2)
- [`paper_bo.md`](paper_bo.md) — campaigns, paper BO, wallet (order sections removed)

