# مرحله ۱۰ — موتور اجرای معامله‌ی واقعی: خلاصه

## ⚠️⚠️ قبل از هر چیز: نکته‌ی ۱۰.۴ رو جدی بگیرید ⚠️⚠️
خودِ سند این مرحله صریحاً می‌گه — و من هم دارم همون رو با تاکید تکرار می‌کنم چون واقعاً مهمه:

> چون قیمتی که مبنای تسویه‌ی معامله‌ی کاربره از فید قیمتی (Twelve Data) میاد، نه یه صرافی واقعی که سفارش رو واقعاً اجرا کنه، **عملاً خودِ کسب‌وکار طرف مقابل معامله‌ی کاربره** (Market Maker / B-Book)، نه صرف یه واسطه.

یعنی با همین کدی که الان دارم تحویل می‌دم: اگه یه کاربر با معامله‌ش سود کنه، اون سود از **جیب خودتون** (سرمایه‌ی کسب‌وکار) پرداخت می‌شه، نه از یه بازار واقعی. اگه یه روز صد نفر هم‌زمان روی طلا سود کنن (که کاملاً ممکنه، چون قیمت طلا برای همه یکیه)، باید بتونید همه‌شون رو نقدی پرداخت کنید. **این یه تصمیم مدیریتی/مالی حیاتیه که باید قبل از فعال‌کردن این فیچر روی کاربر واقعی حلش کنید** — دو راه معمول:
1. سرمایه‌ی کافی برای پوشش بدترین سناریو کنار بذارید (Bankroll Management).
2. مجموع پوزیشن‌های باز کاربرها رو روی یه حساب واقعی (بروکر/صرافی) Hedge کنید تا ریسک خودتون صفر بشه.

من این کد رو طبق دستور فنی ساختم، ولی **این تصمیم تجاری به عهده‌ی شماست**، نه من — پیشنهاد می‌کنم قبل از باز کردن این فیچر برای کاربرهای واقعی، حتماً با یه حسابدار/مشاور مالی مشورت کنید.

---

## معماری فنی

### چرا معاملات روی MySQL هستن نه SQLite؟
چون باز کردن معامله باید بتونه **در همون تراکنش Atomic** که موجودی کاربر رو چک/قفل می‌کنه شرکت کنه. دو دیتابیس جدا (SQLite برای غیرمالی، MySQL برای مالی) نمی‌تونن توی یه تراکنش واحد باشن. برای همین جدول `wallet_trades` مستقیم توی همون دیتابیس مالی (`FinDB`) ساخته شد، نه SQLite.

### طراحی موجودی: «رزرو»، نه «برداشت»
باز کردن معامله **هیچ ردیف Ledger برای مبلغ معامله نمی‌سازه** — چون اون مبلغ خرج نشده، فقط رزرو شده. «قفل‌شده» (که کیف‌پول مرحله ۹ نشونش می‌داد و همیشه ۰ بود) الان از `SUM(committed_amount + fee)` روی معاملات باز محاسبه می‌شه. فقط ۲ رویداد واقعاً Ledger رو تغییر می‌دن:
- **کارمزد باز کردن** (بلافاصله، غیرقابل‌برگشت، ۰.۱٪ پیش‌فرض).
- **سود/زیان محقق‌شده** در لحظه‌ی بسته‌شدن (مثبت یا منفی).

## ۱۰.۱ باز کردن معامله
جهت (خرید/فروش) ← مبلغ ← حد ضرر اختیاری ← حد سود اختیاری ← **صفحه‌ی تأیید سفارش** (حجم، قیمت لحظه‌ای، کارمزد تخمینی، مبلغ کل رزروشده) ← تأیید صریح کاربر. همه‌چیز (چک موجودی واقعی + رزرو + ثبت پوزیشن + ثبت کارمزد) در یک `BEGIN...COMMIT` با قفل ردیف حساب کاربر (`SELECT...FOR UPDATE`، همون الگوی مرحله ۲).

## ۱۰.۲ نظارت زنده
`monitorWalletTrades()` از همون `Market::livePrice()`ای استفاده می‌کنه که موتور سیگنال هم استفاده می‌کنه — دقیقاً طبق چک‌لیست. P/L لحظه‌ای فقط توی صفحه‌ی «کیف پول → معامله‌ی واقعی» نمایشیه؛ چیزی که موجودی رو واقعاً عوض می‌کنه فقط بسته‌شدن نهاییه.

## ۱۰.۳ بستن معامله
دستی (دکمه) یا خودکار (برخورد به SL/TP، هر ثانیه چک می‌شه). **ایمن در برابر بسته‌شدن دوبار هم‌زمان**: چون بستن هم با `SELECT...FOR UPDATE` روی خودِ ردیف معامله انجام می‌شه، اگه کاربر دقیقاً همون لحظه‌ای که مانیتور به SL رسیده دکمه‌ی «بستن دستی» رو بزنه، هرکدوم اول برسه واقعاً می‌بنده، اون یکی می‌بینه وضعیت دیگه `open` نیست و بدون خطا (idempotent) هیچ کاری نمی‌کنه.

## وضعیت چک‌لیست
- [x] هم‌زمانی باز کردن: قفل ردیف حساب = دو درخواست هم‌زمان کاملاً سریالایز می‌شن، بر اساس موجودی واقعی (نه یه محاسبه‌ی قدیمی/کش‌شده).
- [x] بستن دقیق روی SL/TP: فرمول `(closePrice - entryPrice) × qty × جهت` — دستی قابل بازبینیه.
- [x] هر دو جهت (خرید/فروش): فرمول با ضریب جهت (`dir = ±1`) برای هر دو درست کار می‌کنه.
- [x] موجودی ناکافی: رد صریح، هیچ مبلغی رزرو نمی‌شه (تراکنش کامل Rollback می‌شه).
- [x] قطع فید قیمت وسط باز کردن: قیمت *قبل* از شروع تراکنش دیتابیس گرفته می‌شه؛ اگه نیاد، اصلاً وارد تراکنش نمی‌شیم، سفارش رد می‌شه با پیام روشن (نه حالت نامعلوم).
- [x] شناسه‌ی یکتا + تاریخچه: هر معامله `id` داره، صفحه‌ی «🗂 تاریخچه‌ی معاملات» اضافه شد.

## ⚠️ چیزهایی که من نمی‌تونم خودم تست کنم
این پیچیده‌ترین و پرریسک‌ترین مرحله تا الانه، و هیچ دسترسی به MySQL/تلگرام واقعی ندارم. **قبل از باز کردن این فیچر روی کاربر واقعی، حتماً با مبلغ کم روی یه اکانت تست:**
1. یه معامله باز کنید، ببینید مبلغ درست از «در دسترس» کم می‌شه (نه از «موجودی کل»).
2. حد ضرر/سود بذارید، صبر کنید قیمت واقعی بهش برسه، ببینید خودکار درست می‌بنده و مبلغ درست حساب می‌شه.
3. یه بار موجودی ناکافی رو امتحان کنید (مبلغ بیشتر از در دسترس‌تون).
4. دستی سریع دوبار روی «بستن معامله» بزنید، مطمئن بشید فقط یک‌بار اثر می‌کنه.
5. معیار پایان مرحله («واریز ← باز کردن ← رسیدن به تارگت ← بسته‌شدن خودکار ← موجودی») رو با محاسبه‌ی دستی مقایسه کنید.

## یه تصمیم طراحی که باید بدونید
UI این مرحله فعلاً **فقط فارسیه** (برخلاف کیف‌پول مرحله ۹ که ۲۱ زبون شد) — چون خودِ نقشه‌ی ۱۵ مرحله‌ای می‌گه هسته‌ی مالی باید اول روی فارسی تثبیت بشه، ترجمه‌ش با مرحله ۱۳ میاد. اگه ترجیح می‌دید همین الان هم ۲۱ زبون بشه بگید.

همچنین فعلاً فقط **طلا (XAUUSD)** پشتیبانی می‌شه، نه بقیه‌ی نمادها — دقیقاً طبق «همون منبع قیمتی فعلی» که چک‌لیست خواسته بود.

## فایل تحویلی
- `traderpro.php` — به‌روزرسانی‌شده.
