چرخه عمر سفارش (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 فعال شده
مراحل:
مثال:
سفارش ورودی: خرید 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 (منقضی شده)¶
توضیحات: - زمان انقضای سفارش رسیده - سیستم به طور خودکار لغو میکند
مثال:
ویژگیها:
{
"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)
نتیجه:
سناریو 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. موجودی ناکافی در زمان تطبیق¶
2. نماد غیرفعال شده¶
3. انقضای زمان¶
چکلیست توسعه¶
قبل از ایجاد سفارش¶
- [ ] موجودی کافی
- [ ] نماد فعال است
- [ ] زمان در سشن معاملاتی
- [ ] حجم معتبر
- [ ] قیمت معتبر
حین پردازش¶
- [ ] وضعیت به درستی بهروز میشود
- [ ] hold به درستی اعمال میشود
- [ ] خطاها لاگ میشوند
بعد از پردازش¶
- [ ] تسویه انجام شده
- [ ] موجودیها بهروز شده
- [ ] معامله ثبت شده
خلاصه¶
چرخه عمر سفارش: 1. New → ایجاد شده 2. Queued → در صف 3. Validating → بررسی اعتبار 4. Active → در دفتر سفارشات 5. InMatching → در حال تطبیق 6. Partial/Filled → پر شده (جزئی/کامل) 7. Cancelled/Expired → لغو شده
نکات کلیدی: - هر وضعیت دلیل مشخص دارد - تغییرات وضعیت لاگ میشود - موجودیها همیشه امن هستند - خطاها مدیریت میشوند
بعدی: مطالعه رفرنس API - User