feat: 期权交易后端 — 下单+自动结算+后台管理
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\OptionOrder;
|
||||
use App\OptionPair;
|
||||
use App\UsersWallet;
|
||||
use App\AccountLog;
|
||||
use App\CurrencyMatch;
|
||||
use App\Currency;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AutoOptionSettle extends Command
|
||||
{
|
||||
protected $signature = "auto_option_settle";
|
||||
protected $description = "自动结算到期的期权订单";
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$orderIds = OptionOrder::where('status', 0)
|
||||
->where('delivery_time', '<=', now())
|
||||
->pluck('id');
|
||||
|
||||
if ($orderIds->isEmpty()) return;
|
||||
|
||||
foreach ($orderIds as $orderId) {
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$affected = OptionOrder::where('id', $orderId)->where('status', 0)
|
||||
->update(['status' => 99]);
|
||||
if ($affected === 0) {
|
||||
DB::rollBack();
|
||||
continue;
|
||||
}
|
||||
|
||||
$order = OptionOrder::lockForUpdate()->find($orderId);
|
||||
$pair = OptionPair::find($order->pair_id);
|
||||
$match = $pair ? CurrencyMatch::find($pair->currency_match_id) : null;
|
||||
$currency = $match ? Currency::find($match->currency_id) : null;
|
||||
$close_price = $currency ? sprintf("%.6f", $currency->price) : '0';
|
||||
|
||||
if (bccomp($close_price, '0', 6) <= 0) {
|
||||
$order->update(['status' => 0]);
|
||||
DB::commit();
|
||||
$this->warn("Order #{$orderId}: close_price=0, skip");
|
||||
continue;
|
||||
}
|
||||
|
||||
$cmp = bccomp($close_price, sprintf("%.6f", $order->open_price), 6);
|
||||
$win = $order->direction == 'up' ? $cmp > 0 : $cmp < 0;
|
||||
|
||||
$income = $win
|
||||
? bcmul(sprintf("%.6f", $order->amount), bcdiv(sprintf("%.6f", $order->profit_rate), '100', 8), 6)
|
||||
: bcmul(sprintf("%.6f", $order->amount), '-1', 6);
|
||||
|
||||
$order->update([
|
||||
'close_price' => $close_price,
|
||||
'income' => $income,
|
||||
'status' => $win ? 1 : 2,
|
||||
]);
|
||||
|
||||
if ($win) {
|
||||
$wallet = UsersWallet::where('user_id', $order->user_id)
|
||||
->where('currency', 3)->lockForUpdate()->first();
|
||||
if ($wallet) {
|
||||
$return_amount = bcadd(sprintf("%.6f", $order->amount), $income, 6);
|
||||
$before = $wallet->legal_balance;
|
||||
$wallet->legal_balance = bcadd($wallet->legal_balance, $return_amount, 6);
|
||||
$wallet->save();
|
||||
AccountLog::insertLog(
|
||||
['user_id' => $order->user_id, 'value' => $return_amount, 'info' => 'Option Win - ' . $order->symbol, 'type' => AccountLog::MICRO_TRADE_CLOSE_SETTLE, 'currency' => 3],
|
||||
['balance_type' => 1, 'wallet_id' => $wallet->id, 'lock_type' => 0, 'before' => $before, 'change' => $return_amount, 'after' => $wallet->legal_balance]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
$this->info("Order #{$orderId} settled: " . ($win ? 'WIN' : 'LOSE'));
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
$this->error("Order #{$orderId} error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user