# Orders

The Go SDK covers placing, modifying, and canceling orders across all supported exchanges.

The first argument to `PlaceOrder`, `ModifyOrder`, and `CancelOrder` is the **variety** string. Use `"regular"` for standard orders.

## Order Parameters

### Exchanges

| Exchange | Code | Description |
|----------|------|-------------|
| NSE | `arrow.ExchangeNSE` | National Stock Exchange - Equity |
| BSE | `arrow.ExchangeBSE` | Bombay Stock Exchange - Equity |
| NFO | `arrow.ExchangeNFO` | NSE Futures & Options |
| BFO | `arrow.ExchangeBFO` | BSE Futures & Options |
| MCX | `arrow.ExchangeMCX` | Multi Commodity Exchange (permissions / instrument segment) |
| MCXFO | `arrow.ExchangeMCXFO` | MCX Futures & Options (orders, quotes, margin) |
| INDEX | `arrow.ExchangeINDEX` | Index segment (utility / option-chain APIs) |
| NCD | `arrow.ExchangeNCD` | NSE Currency Derivatives |
| BCD | `arrow.ExchangeBCD` | BSE Currency Derivatives |
| NSESLBM | `arrow.ExchangeNSESLBM` | NSE SLBM |

!!! note "MCX vs MCXFO"
    Use **`ExchangeMCXFO`** for place/modify order, quotes, and margin. **`ExchangeMCX`** is for permission checks and the `/mcx` instrument download segment. Position and trade responses return `"MCXFO"`.

### Order Types

| Type | Code | Description |
|------|------|-------------|
| Limit | `arrow.OrderTypeLimit` (`LMT`) | Execute at specified price or better |
| Market | `arrow.OrderTypeMarket` (`MKT`) | Plain market orders are disabled by default. Set `MarketProtection: true` (`mpp`) to mimic a market order |
| Stop Loss Limit | `arrow.OrderTypeSLLMT` (`SL-LMT`) | Limit order activated at trigger |
| Stop Loss Market | `arrow.OrderTypeSLMKT` (`SL-MKT`) | Market order activated at trigger |
| Stop Loss (legacy) | `arrow.OrderTypeSL` (`SL`) | Legacy alias |
| Stop Loss Market (legacy) | `arrow.OrderTypeSLM` (`SL-M`) | Legacy alias |

### Product Types

| Product | Code | Description | Settlement |
|---------|------|-------------|------------|
| Intraday | `arrow.ProductMIS` (`I`) | Same-day position closure | Auto-squared off at 3:15 PM |
| Cash & Carry | `arrow.ProductCNC` (`C`) | Equity delivery orders | T+1 settlement |
| Normal | `arrow.ProductNRML` (`M`) | F&O margin orders | Standard margin |

### Order Validity

| Validity | Code | Description |
|----------|------|-------------|
| Day | `arrow.ValidityDAY` | Valid until market close |
| IOC | `arrow.ValidityIOC` | Immediate or Cancel |
| GTC | `arrow.ValidityGTC` | Good Till Cancelled |

### Transaction Types

| Type | Code | Description |
|------|------|-------------|
| Buy | `arrow.TransactionTypeBuy` (`B`) | Buy transaction |
| Sell | `arrow.TransactionTypeSell` (`S`) | Sell transaction |

!!! note "Market orders and `mpp`"
    Under current regulations, **plain `MKT` orders are disabled by default** on the API. Set **`MarketProtection: true`** on `OrderRequest` (`json:"mpp"`) to send a **`LIMIT`** order at the **Upper Limit** or **DPR**, **depending on instrument type**, and mimic market-style execution. In rare cases of **extreme volatility or sharp price movement**, this can still leave the order **open** (fully or partially unfilled).

!!! note "Variety"
    There is no `Variety` type in Go. Pass `"regular"` as the first argument. Modify and cancel also take an explicit variety (Python hardcodes `/order/regular/{id}`).

## Place Order

`PlaceOrder` returns `*OrderResponse`. The order number is `order.Data.OrderNo`. All quantity and price fields on `OrderRequest` are **strings**.

### Basic Example

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeNSE),
    Symbol:          "RELIANCE-EQ",
    Quantity:        "1",
    DisclosedQty:    "0",
    Product:         string(arrow.ProductCNC),
    OrderType:       string(arrow.OrderTypeLimit),
    TransactionType: string(arrow.TransactionTypeBuy),
    Price:           "1450.0",
    Validity:        string(arrow.ValidityDAY),
})
if err != nil {
    log.Fatal(err)
}
fmt.Println("Order placed:", order.Data.OrderNo)
```

### Market-style order (`mpp`)

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:         string(arrow.ExchangeNSE),
    Symbol:           "RELIANCE-EQ",
    Quantity:         "10",
    DisclosedQty:     "0",
    Product:          string(arrow.ProductMIS),
    OrderType:        string(arrow.OrderTypeMarket),
    TransactionType:  string(arrow.TransactionTypeBuy),
    Price:            "0",
    Validity:         string(arrow.ValidityDAY),
    MarketProtection: true,
})
```

### Limit Order

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeNSE),
    Symbol:          "INFY-EQ",
    Quantity:        "5",
    Product:         string(arrow.ProductCNC),
    OrderType:       string(arrow.OrderTypeLimit),
    TransactionType: string(arrow.TransactionTypeBuy),
    Price:           "1500.50",
    Validity:        string(arrow.ValidityDAY),
})
```

### Stop Loss Order

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeNSE),
    Symbol:          "TCS-EQ",
    Quantity:        "2",
    Product:         string(arrow.ProductCNC),
    OrderType:       string(arrow.OrderTypeSLLMT),
    TransactionType: string(arrow.TransactionTypeSell),
    Price:           "3400.0",
    TriggerPrice:    "3410.0",
    Validity:        string(arrow.ValidityDAY),
})
```

### F&O Order

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeNFO),
    Symbol:          "NIFTY02JAN25C26000",
    Quantity:        "75",
    Product:         string(arrow.ProductNRML),
    OrderType:       string(arrow.OrderTypeLimit),
    TransactionType: string(arrow.TransactionTypeBuy),
    Price:           "150.0",
    Validity:        string(arrow.ValidityDAY),
})
```

### MCXFO Order

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeMCXFO),
    Symbol:          "GOLDPETAL31JUL26F",
    Quantity:        "1",
    DisclosedQty:    "0",
    Product:         string(arrow.ProductMIS),
    OrderType:       string(arrow.OrderTypeLimit),
    TransactionType: string(arrow.TransactionTypeBuy),
    Price:           "14300.0",
    Validity:        string(arrow.ValidityDAY),
    Remarks:         "strategy_1",
    TriggerPrice:    "0",
})
if err != nil {
    log.Fatal(err)
}

_, err = client.ModifyOrder("regular", order.Data.OrderNo, arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeMCXFO),
    Symbol:          "GOLDPETAL31JUL26F",
    Quantity:        "1",
    DisclosedQty:    "0",
    Product:         string(arrow.ProductMIS),
    OrderType:       string(arrow.OrderTypeLimit),
    TransactionType: string(arrow.TransactionTypeBuy),
    Price:           "14320.0",
    Validity:        string(arrow.ValidityDAY),
    TriggerPrice:    "0",
})
```

### Iceberg Order (Disclosed Quantity)

```go
order, err := client.PlaceOrder("regular", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeNSE),
    Symbol:          "RELIANCE-EQ",
    Quantity:        "1000",
    DisclosedQty:    "100",
    Product:         string(arrow.ProductCNC),
    OrderType:       string(arrow.OrderTypeLimit),
    TransactionType: string(arrow.TransactionTypeBuy),
    Price:           "1450.0",
    Validity:        string(arrow.ValidityDAY),
})
```

## Modify Order

```go
resp, err := client.ModifyOrder("regular", "24012400000321", arrow.OrderRequest{
    Exchange:        string(arrow.ExchangeNSE),
    Symbol:          "RELIANCE-EQ",
    Quantity:        "2",
    Price:           "1500.0",
    DisclosedQty:    "0",
    Product:         string(arrow.ProductCNC),
    TransactionType: string(arrow.TransactionTypeBuy),
    OrderType:       string(arrow.OrderTypeLimit),
    Validity:        string(arrow.ValidityDAY),
    Remarks:         "Modified order",
    TriggerPrice:    "1480.0",
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(resp.Message)
```

!!! warning "Modification Restrictions"
    - Cannot modify executed orders
    - Cannot change exchange or symbol
    - Cannot change transaction type (Buy/Sell)

## Cancel Order

### Cancel Single Order

```go
if err := client.CancelOrder("regular", "24012400000321"); err != nil {
    log.Fatal(err)
}
```

### Cancel All Orders

```go
if err := client.CancelAllOrders(); err != nil {
    log.Fatal(err)
}
```

!!! info "Bulk Cancel"
    `CancelAllOrders` is an SDK convenience wrapper (not a single REST route). It fetches the order book and cancels `OPEN`, `TRIGGER_PENDING`, and `PARTIALLY_FILLED` orders **sequentially** using variety `"regular"`.

    Orders still in `PENDING` / `PENDINGNEW` / `PENDING_NEW` are skipped. If any remain pending, the method returns an error (`exchange connectivity binary is down`). The first cancel failure is also returned.

## Margin helpers

```go
margin, err := client.GetMargin(arrow.MarginRequest{
    Exchange:         arrow.ExchangeNSE,
    Symbol:           "RELIANCE-EQ",
    Quantity:         "1",
    Price:            "1450.0",
    Product:          arrow.ProductCNC,
    TransactionType:  arrow.TransactionTypeBuy,
    Order:            arrow.OrderTypeLimit,
    IncludePositions: true,
})
if err != nil {
    log.Fatal(err)
}
fmt.Println("Required margin:", margin.Data.RequiredMargin)

basket, err := client.GetBasketMargin(arrow.BasketMarginRequest{
    Orders: []arrow.MarginRequest{{
        Exchange:        arrow.ExchangeMCXFO,
        Symbol:          "GOLDPETAL31JUL26F",
        Quantity:        "1",
        Price:           "14300.0",
        Product:         arrow.ProductMIS,
        TransactionType: arrow.TransactionTypeBuy,
        Order:           arrow.OrderTypeLimit,
    }},
    IncludePositions: false,
})
```

The SDK sends `symbol` (trading symbol) in margin requests. Basket margin is `{ "orders": [...], "includePositions": bool }`, not a bare JSON array.

Live `GetMargin` response: `requiredMargin`, `minimumCashRequired`, `marginUsedAfterTrade`, `charge`.

Live `GetBasketMargin` response: `final_margin`, `initial_margin`, `orders` (each with `margin`, `symid`, `charge`).

## Order Tracking

### Get Order Details

```go
details, err := client.GetOrder("24012400000321")
if err != nil {
    log.Fatal(err)
}
for _, d := range details.Data {
    fmt.Println(d.OrderStatus, d.ReportType, d.FillShares, d.AveragePrice)
}
```

### Order Status Types

| Status | Description | Next Action |
|--------|-------------|-------------|
| `PENDING` | Order submitted, awaiting confirmation | Monitor; `CancelAllOrders` will not cancel these |
| `OPEN` | Order active in the market | Can modify or cancel |
| `COMPLETE` | Order fully executed | Review execution details |
| `CANCELLED` | Order cancelled by user/system | No further action |
| `REJECTED` | Order rejected by exchange | Check rejection reason |

### Get Order Book

```go
orders, err := client.GetOrderBook()
if err != nil {
    log.Fatal(err)
}
for _, o := range orders {
    fmt.Printf("%s %s %s %s @ %s status=%s\n",
        o.ID, o.Symbol, o.TransactionType, o.Quantity, o.Price, o.OrderStatus)
}
```

### Get Trade Book

```go
trades, err := client.GetTradeBook()
if err != nil {
    log.Fatal(err)
}
for _, t := range trades {
    fmt.Printf("%s %s fill %s @ %s time=%s\n",
        t.OrderID, t.Symbol, t.Quantity, t.FillPrice, t.FillTime)
}
```

!!! note
    Trade rows use **`OrderID`**, not `orderNo`.

## Order Book Fields

| Field | Type | Description |
|-------|------|-------------|
| `ID` | string | Order ID |
| `Exchange` | string | Exchange code |
| `Symbol` | string | Trading symbol |
| `Price` | string | Order price |
| `Quantity` | string | Order quantity |
| `Product` | string | Product type (`I` / `C` / `M`) |
| `OrderStatus` | string | Current status |
| `TransactionType` | string | Buy (`B`) / Sell (`S`) |
| `Order` | string | Order type |
| `FillShares` | string | Quantity filled in this update |
| `AveragePrice` | string | Average fill price |
| `ExchangeOrderID` | string | Exchange order number |
| `OrderTime` | string | Order timestamp |
| `RejectReason` | string | Rejection reason (if any) |

## Complete Example

```go
package main

import (
    "fmt"
    "log"
    "os"

    "github.com/arrow-trade/go-arrow/arrow"
)

func main() {
    client := arrow.NewClient(os.Getenv("ARROW_APP_ID"), os.Getenv("ARROW_APP_SECRET"))
    if err := client.AutoLogin(
        os.Getenv("ARROW_USER_ID"),
        os.Getenv("ARROW_PASSWORD"),
        os.Getenv("ARROW_TOTP_SECRET"),
    ); err != nil {
        log.Fatal(err)
    }

    order, err := client.PlaceOrder("regular", arrow.OrderRequest{
        Exchange:        string(arrow.ExchangeNSE),
        Symbol:          "RELIANCE-EQ",
        Quantity:        "1",
        DisclosedQty:    "0",
        Product:         string(arrow.ProductCNC),
        OrderType:       string(arrow.OrderTypeLimit),
        TransactionType: string(arrow.TransactionTypeBuy),
        Price:           "1450.0",
        Validity:        string(arrow.ValidityDAY),
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Order placed:", order.Data.OrderNo)

    details, err := client.GetOrder(order.Data.OrderNo)
    if err != nil {
        log.Fatal(err)
    }
    if len(details.Data) > 0 && details.Data[0].OrderStatus == "OPEN" {
        _, err = client.ModifyOrder("regular", order.Data.OrderNo, arrow.OrderRequest{
            Exchange:        string(arrow.ExchangeNSE),
            Symbol:          "RELIANCE-EQ",
            Quantity:        "1",
            Price:           "1455.0",
            Product:         string(arrow.ProductCNC),
            TransactionType: string(arrow.TransactionTypeBuy),
            OrderType:       string(arrow.OrderTypeLimit),
            Validity:        string(arrow.ValidityDAY),
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Order modified")
    }

    book, _ := client.GetOrderBook()
    trades, _ := client.GetTradeBook()
    fmt.Println("Orders today:", len(book), "trades:", len(trades))
}
```

## Error Handling

```go
order, err := client.PlaceOrder("regular", req)
if err != nil {
    log.Printf("Order failed: %v", err)
    return
}
```

### Common Order Errors

| Error | Cause | Solution |
|-------|-------|----------|
| Insufficient margin | Not enough funds | Add funds or reduce quantity |
| Price outside DPR | Price beyond daily range | Adjust price within limits |
| Invalid symbol | Symbol not found | Verify symbol format |
| Market closed | Outside trading hours | Wait for market hours |
| Quantity not in lot | F&O lot size mismatch | Use correct lot multiples |

!!! tip "Best Practices"
    - Always validate order parameters before submission
    - Check `err` on every REST call
    - Monitor position limits and margin with `GetMargin` / `GetLimits`
    - Use `Remarks` for order identification in bulk operations (max 16 characters)
