پرش به محتویات

چرخه عمر سفارش (Order Lifecycle)

مقدمه

این سند به طور کامل چرخه عمر یک سفارش را از لحظه ایجاد تا پایان (موفق یا ناموفق) توضیح می‌دهد.

نمودار کامل چرخه عمر

stateDiagram-v2
    [*] --> New: کاربر سفارش را ثبت می‌کند

    New --> Queued: ارسال به سیستم
    Queued --> Validating: در حال اعتبارسنجی

    Validating --> Rejected: خطای اعتبارسنجی
    Validating --> Active: تایید شد

    Rejected --> [*]: ثبت در تاریخچه

    Active --> InMatching: در صف تطبیق

    InMatching --> Partial: بخشی پر شد
    InMatching --> Filled: کامل پر شد
    InMatching --> NoMatch: پیدا نشد

    Partial --> InMatching: ادامه تطبیق
    Partial --> Cancelled: کاربر لغو کرد
    Partial --> Expired: منقضی شد

    NoMatch --> Active: در دفتر سفارشات
    NoMatch --> Cancelled: لغو شد

    Active --> Cancelled: کاربر لغو کرد
    Active --> Expired: منقضی شد

    Filled --> [*]: تسویه و پایان
    Cancelled --> [*]: آزادسازی و پایان
    Expired --> [*]: آزادسای و پایان

    note right of New: اولین وضعیت
    note right of Queued: در صف پردازش
    note right of Validating: بررسی موجودی و اعتبار
    note right of Rejected: دلیل رد ذخیره می‌شود
    note right of Active: در دفتر سفارشات
    note right of InMatching: در حال جستجوی جفت
    note right of Partial: 10% از 100% پر شده
    note right of Filled: 100% پر شده
    note right of Cancelled: توسط کاربر یا سیستم
    note right of Expired: زمان سفارش به پایان رسیده

جزئیات هر وضعیت

1. New (جدید)

توضیحات: - کاربر سفارش را از طریق API ثبت کرده - سیستم درخواست را دریافت کرده - هنوز پردازش نشده

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "new",
  "created_at": "2025-12-30T10:00:00Z",
  "updated_at": "2025-12-30T10:00:00Z"
}

مدت زمان: میلی‌ثانیه


2. Queued (در صف)

توضیحات: - سفارش در صف پردازش قرار گرفته - در انتظار بررسی توسط سیستم اعتبارسنجی

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "queued",
  "queue_position": 5,
  "created_at": "2025-12-30T10:00:00Z",
  "updated_at": "2025-12-30T10:00:01Z"
}

مدت زمان: چند ثانیه


3. Validating (در حال اعتبارسنجی)

توضیحات: - سیستم در حال بررسی: - موجودی کافی - اعتبار توکن - محدودیت‌های سفارش - زمان معاملاتی

مراحل اعتبارسنجی:

1. بررسی موجودی کیف پول
2. بررسی محدودیت‌های نماد
3. بررسی زمان سشن
4. بررسی محدودیت‌های کاربر
5. تایید یا رد


4. Rejected (رد شده)

توضیحات: - سفارش به دلیل خطای اعتبارسنجی رد شده - دلیل رد ذخیره می‌شود

دلایل رایج: - ❌ موجودی ناکافی - ❌ حجم کمتر از حداقل - ❌ قیمت خارج از محدوده - ❌ نماد غیرفعال - ❌ زمان خارج از سشن - ❌ محدودیت دسترسی

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "rejected",
  "rejection_reasons": [
    "insufficient_balance",
    "quantity_below_minimum"
  ],
  "created_at": "2025-12-30T10:00:00Z",
  "updated_at": "2025-12-30T10:00:02Z"
}

نمونه پاسخ:

{
  "detail": [
    {
      "loc": ["body", "quantity"],
      "msg": "value is less than minimum",
      "type": "value_error.number.not_ge",
      "ctx": {"limit_value": 0.0001}
    }
  ]
}


5. Active (فعال)

توضیحات: - سفارش تایید شده و در دفتر سفارشات قرار گرفته - منتظر تطبیق با سفارشات دیگر

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "active",
  "symbol": "BTC-IRR",
  "side": "buy",
  "price": "100000000",
  "quantity": "0.5",
  "filled": "0.0",
  "available": "0.5",
  "created_at": "2025-12-30T10:00:02Z",
  "updated_at": "2025-12-30T10:00:02Z"
}

در دفتر سفارشات:

Bids (Buy):
- 100M: 0.5 BTC (ord_123)

Asks (Sell):
- 101M: 0.3 BTC (ord_456)
- 102M: 0.6 BTC (ord_789)


6. InMatching (در حال تطبیق)

توضیحات: - سفارش در حال جستجوی جفت مناسب - موتور Matching Engine فعال شده

مراحل:

1. دریافت سفارش
2. جستجو در طرف مقابل
3. بررسی قیمت
4. بررسی حجم
5. ایجاد معامله

مثال:

سفارش ورودی: خرید 0.5 BTC @ 100M

جستجو در فروش:
- 101M: 0.3 BTC ❌ (قیمت بالاتر)
- 102M: 0.6 BTC ❌ (قیمت بالاتر)

نتیجه: تطبیق پیدا نکرد


7. Partial (پر شده جزئی)

توضیحات: - بخشی از سفارش پر شده - بقیه هنوز فعال است

مثال:

سفارش اولیه: خرید 0.5 BTC @ 100M

تطبیق با:
- فروش 0.3 BTC @ 99M ✅

نتیجه:
- پر شده: 0.3 BTC
- باقی مانده: 0.2 BTC
- وضعیت: Partial

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "partial",
  "symbol": "BTC-IRR",
  "side": "buy",
  "price": "100000000",
  "quantity": "0.5",
  "filled": "0.3",
  "available": "0.2",
  "trades": [
    {
      "trade_id": "trade_456",
      "quantity": "0.3",
      "price": "99000000",
      "created_at": "2025-12-30T10:00:05Z"
    }
  ],
  "updated_at": "2025-12-30T10:00:05Z"
}


8. Filled (پر شده کامل)

توضیحات: - تمام حجم سفارش پر شده - معامله کامل شده - تسویه انجام شده

مثال:

سفارش اولیه: خرید 0.5 BTC @ 100M

تطبیق‌ها:
1. 0.3 BTC @ 99M
2. 0.2 BTC @ 100M

نتیجه:
- کل پر شده: 0.5 BTC
- وضعیت: Filled

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "filled",
  "symbol": "BTC-IRR",
  "side": "buy",
  "price": "100000000",
  "quantity": "0.5",
  "filled": "0.5",
  "available": "0.0",
  "trades": [
    {
      "trade_id": "trade_456",
      "quantity": "0.3",
      "price": "99000000"
    },
    {
      "trade_id": "trade_789",
      "quantity": "0.2",
      "price": "100000000"
    }
  ],
  "updated_at": "2025-12-30T10:00:10Z"
}


9. Cancelled (لغو شده)

توضیحات: - سفارش توسط کاربر یا سیستم لغو شده - موجودی قفل شده آزاد می‌شود

دلایل: - ✅ درخواست کاربر (POST /orders/{uid}/cancel) - ✅ انقضای زمان (برای سفارشات با expire_at) - ✅ خطای سیستم

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "cancelled",
  "cancel_reason": "user_request",
  "symbol": "BTC-IRR",
  "side": "buy",
  "quantity": "0.5",
  "filled": "0.0",
  "available": "0.0",
  "cancelled_at": "2025-12-30T10:05:00Z",
  "updated_at": "2025-12-30T10:05:00Z"
}

آزادسازی موجودی:

قبل از لغو:
- کیف پول IRR: 100M
- Hold: 50M
- Available: 50M

بعد از لغو:
- کیف پول IRR: 100M
- Hold: 0
- Available: 100M


10. Expired (منقضی شده)

توضیحات: - زمان انقضای سفارش رسیده - سیستم به طور خودکار لغو می‌کند

مثال:

سفارش:
- expire_at: 2025-12-30T10:10:00Z
- زمان فعلی: 2025-12-30T10:10:01Z

عمل: لغو خودکار

ویژگی‌ها:

{
  "uid": "ord_123",
  "status": "expired",
  "symbol": "BTC-IRR",
  "side": "buy",
  "quantity": "0.5",
  "filled": "0.0",
  "expired_at": "2025-12-30T10:10:00Z",
  "updated_at": "2025-12-30T10:10:00Z"
}


گردش کار کامل یک سفارش

سناریو 1: سفارش موفق (پر شده کامل)

sequenceDiagram
    participant User
    participant API
    participant Queue
    participant Validator
    participant MatchingEngine
    participant OrderBook
    participant DB
    participant Wallet

    User->>API: POST /orders (0.5 BTC @ 100M)
    API->>Queue: افزودن به صف
    Queue->>Validator: درخواست اعتبارسنجی

    Validator->>Wallet: بررسی موجودی
    Wallet-->>Validator: موجودی کافی (100M)

    Validator->>Validator: بررسی محدودیت‌ها
    Validator-->>Queue: تایید
    Queue->>DB: ذخیره status: queued

    DB->>MatchingEngine: ارسال سفارش
    MatchingEngine->>OrderBook: جستجوی جفت

    Note over MatchingEngine: سفارش فروش 0.5 BTC @ 100M پیدا شد

    MatchingEngine->>DB: به‌روزرسانی status: filled
    DB->>Wallet: تسویه
    Wallet-->>DB: تایید تسویه

    DB->>API: سفارش کامل شد
    API->>User: پاسخ (status: filled)

زمان‌بندی:

T+0ms: درخواست کاربر
T+10ms: تایید اعتبار
T+15ms: ذخیره در DB
T+20ms: ارسال به Matching Engine
T+50ms: تطبیق انجام شد
T+55ms: تسویه
T+60ms: پاسخ به کاربر

سناریو 2: سفارش جزئی

sequenceDiagram
    participant User
    participant API
    participant MatchingEngine
    participant OrderBook
    participant DB

    User->>API: POST /orders (0.5 BTC @ 100M)
    API->>MatchingEngine: ارسال سفارش

    MatchingEngine->>OrderBook: جستجو
    OrderBook-->>MatchingEngine: یافت 0.3 BTC @ 99M

    MatchingEngine->>DB: ذخیره status: partial
    DB->>MatchingEngine: تایید

    MatchingEngine->>OrderBook: ادامه جستجو
    OrderBook-->>MatchingEngine: یافت نشد

    MatchingEngine->>DB: به‌روزرسانی (0.3 پر شده)
    API->>User: پاسخ (status: partial)

نتیجه:

سفارش: 0.5 BTC
پر شده: 0.3 BTC
باقی مانده: 0.2 BTC (در دفتر)

سناریو 3: سفارش رد شده

sequenceDiagram
    participant User
    participant API
    participant Validator
    participant DB

    User->>API: POST /orders (0.5 BTC @ 100M)
    API->>Validator: درخواست اعتبارسنجی

    Validator->>Validator: بررسی موجودی
    Validator-->>API: خطا: موجودی ناکافی

    API->>DB: ذخیره status: rejected
    API->>User: پاسخ خطا

پاسخ:

{
  "detail": [
    {
      "loc": ["body", "quantity"],
      "msg": "insufficient balance",
      "type": "value_error"
    }
  ]
}

سناریو 4: سفارش لغو شده

sequenceDiagram
    participant User
    participant API
    participant MatchingEngine
    participant OrderBook
    participant DB
    participant Wallet

    Note over User,DB: سفارش در وضعیت Active

    User->>API: POST /orders/{uid}/cancel
    API->>MatchingEngine: درخواست لغو

    MatchingEngine->>OrderBook: حذف سفارش
    OrderBook-->>MatchingEngine: تایید

    MatchingEngine->>DB: به‌روزرسانی status: cancelled
    DB->>Wallet: آزادسازی hold
    Wallet-->>DB: تایید

    API->>User: پاسخ (status: cancelled)

جزئیات فنی

1. ذخیره‌سازی در دیتابیس

جدول Orders:

CREATE TABLE orders (
    uid VARCHAR(50) PRIMARY KEY,
    user_id VARCHAR(50) NOT NULL,
    wallet_id VARCHAR(50) NOT NULL,
    symbol VARCHAR(20) NOT NULL,
    side VARCHAR(10) NOT NULL,
    type VARCHAR(20) NOT NULL,
    price DECIMAL(20, 0),
    quantity DECIMAL(20, 8),
    filled DECIMAL(20, 8) DEFAULT 0,
    status VARCHAR(20) NOT NULL,
    rejection_reasons JSON,
    cancel_reason VARCHAR(50),
    expire_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_orders_symbol ON orders(symbol);
CREATE INDEX idx_orders_status ON orders(status);

2. مدیریت Hold

مکانیزم:

def create_order(user_id, symbol, side, quantity, price):
    # محاسبه مبلغ کل
    if side == "buy":
        total_amount = quantity * price
        currency = "IRR"
    else:
        total_amount = quantity
        currency = symbol.split("-")[0]

    # بررسی موجودی
    wallet = get_wallet(user_id, currency)
    if wallet.available < total_amount:
        raise InsufficientBalance()

    # ایجاد hold
    hold_amount = total_amount
    wallet.hold += hold_amount
    wallet.available -= hold_amount
    save_wallet(wallet)

    # ایجاد سفارش
    order = Order(
        uid=generate_uid(),
        user_id=user_id,
        wallet_id=wallet.uid,
        symbol=symbol,
        side=side,
        type="limit",
        price=price,
        quantity=quantity,
        filled=0,
        status="queued"
    )
    save_order(order)

    return order

آزادسازی hold:

def cancel_order(order_uid):
    order = get_order(order_uid)

    if order.status not in ["active", "partial"]:
        raise InvalidOperation()

    # محاسبه hold باقی مانده
    remaining = order.quantity - order.filled
    if order.side == "buy":
        hold_amount = remaining * order.price
        currency = "IRR"
    else:
        hold_amount = remaining
        currency = order.symbol.split("-")[0]

    # آزادسازی
    wallet = get_wallet(order.wallet_id)
    wallet.hold -= hold_amount
    wallet.available += hold_amount
    save_wallet(wallet)

    # به‌روزرسانی سفارش
    order.status = "cancelled"
    order.cancel_reason = "user_request"
    save_order(order)

    return order

3. Matching Engine

الگوریتم:

def match_order(new_order):
    # جستجوی سفارش مطابق
    if new_order.side == "buy":
        # جستجو در فروش‌ها (Asks)
        matching_orders = get_asks(
            symbol=new_order.symbol,
            max_price=new_order.price,
            limit=10
        )
    else:
        # جستجو در خرید‌ها (Bids)
        matching_orders = get_bids(
            symbol=new_order.symbol,
            min_price=new_order.price,
            limit=10
        )

    # تطبیق
    for match_order in matching_orders:
        # محاسبه حجم معامله
        trade_quantity = min(
            new_order.quantity - new_order.filled,
            match_order.quantity - match_order.filled
        )

        # قیمت معامله (قیمت سفارش قدیمی‌تر)
        trade_price = match_order.price

        # ایجاد معامله
        create_trade(
            symbol=new_order.symbol,
            price=trade_price,
            quantity=trade_quantity,
            maker_order=match_order,
            taker_order=new_order
        )

        # به‌روزرسانی سفارشات
        new_order.filled += trade_quantity
        match_order.filled += trade_quantity

        # بررسی تکمیل سفارشات
        if new_order.filled == new_order.quantity:
            new_order.status = "filled"
            break

        if match_order.filled == match_order.quantity:
            match_order.status = "filled"

    # اگر بقیه مانده
    if new_order.filled > 0 and new_order.filled < new_order.quantity:
        new_order.status = "partial"
    elif new_order.filled == 0:
        new_order.status = "active"

    save_order(new_order)
    return new_order

مدیریت خطاها در چرخه عمر

خطاهای زمان اجرا

1. موجودی ناکافی در زمان تطبیق

وضعیت: سفارش Active است
مشکل: کاربر موجودی را برداشته
عمل: سیستم سفارش را به Rejected تغییر می‌دهد

2. نماد غیرفعال شده

وضعیت: سفارش در دفتر
مشکل: نماد غیرفعال شد
عمل: سیستم سفارش را لغو می‌کند

3. انقضای زمان

وضعیت: سفارش Active
مشکل: زمان expire_at رسید
عمل: سیستم سفارش را به Expired تغییر می‌دهد

چک‌لیست توسعه

قبل از ایجاد سفارش

  • [ ] موجودی کافی
  • [ ] نماد فعال است
  • [ ] زمان در سشن معاملاتی
  • [ ] حجم معتبر
  • [ ] قیمت معتبر

حین پردازش

  • [ ] وضعیت به درستی به‌روز می‌شود
  • [ ] hold به درستی اعمال می‌شود
  • [ ] خطاها لاگ می‌شوند

بعد از پردازش

  • [ ] تسویه انجام شده
  • [ ] موجودی‌ها به‌روز شده
  • [ ] معامله ثبت شده

خلاصه

چرخه عمر سفارش: 1. New → ایجاد شده 2. Queued → در صف 3. Validating → بررسی اعتبار 4. Active → در دفتر سفارشات 5. InMatching → در حال تطبیق 6. Partial/Filled → پر شده (جزئی/کامل) 7. Cancelled/Expired → لغو شده

نکات کلیدی: - هر وضعیت دلیل مشخص دارد - تغییرات وضعیت لاگ می‌شود - موجودی‌ها همیشه امن هستند - خطاها مدیریت می‌شوند


بعدی: مطالعه رفرنس API - User