367 lines
14 KiB
PHP
367 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\InsuranceClaimApply;
|
|
use App\InsuranceRule;
|
|
use App\Setting;
|
|
use App\UsersInsurance;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use App\Logic\MicroTradeLogic;
|
|
use App\Users;
|
|
use App\CurrencyQuotation;
|
|
use App\Currency;
|
|
use App\MicroSecond;
|
|
use App\UsersWallet;
|
|
use App\MicroOrder;
|
|
use App\MarketHour;
|
|
use App\CurrencyMatch;
|
|
use App\InsuranceType;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Redis;
|
|
|
|
class MicroOrderController extends Controller
|
|
{
|
|
|
|
/**
|
|
* 取允许支付的币种
|
|
*
|
|
* @return \Illuminate\Http\JsonResponse
|
|
*/
|
|
public function getPayableCurrencies()
|
|
{
|
|
$currencies = Currency::with('microNumbers')
|
|
->where('is_micro', 1)
|
|
->get();
|
|
|
|
$user = Users::getAuthUser();
|
|
$currencies->transform(function ($item, $key) use ($user) {
|
|
// 追加上险种
|
|
$insurance_types = InsuranceType::where('currency_id', $item->id)
|
|
->get();
|
|
|
|
$item->setAttribute('insurance_types', $insurance_types);
|
|
|
|
// 追加上用户的钱包
|
|
$wallet = UsersWallet::where('user_id', $user->id)
|
|
->where('currency', $item->id)
|
|
->first();
|
|
if ($wallet) {
|
|
$micro_with_insurance = bc_add($wallet->micro_balance, $wallet->insurance_balance);
|
|
$wallet->setAttribute('micro_with_insurance', $micro_with_insurance);
|
|
}
|
|
$item->setAttribute('user_wallet', $wallet);
|
|
// 追加上用户买的保险
|
|
$user_insurance = UsersInsurance::where('user_id', $user->id)
|
|
->whereHas('insurance_type', function ($query) use ($item) {
|
|
$query->where('currency_id', $item->id);
|
|
})->where('status', 1)->first();
|
|
$item->setAttribute('user_insurance', $user_insurance);
|
|
return $item;
|
|
});
|
|
return $this->success($currencies);
|
|
}
|
|
|
|
/**
|
|
* 获取绑定的开仓时间
|
|
*/
|
|
public function getBindSeconds(Request $request)
|
|
{
|
|
$currencyMatch = CurrencyMatch::query()->find($request->currency_match_id);
|
|
|
|
return $this->success($currencyMatch->microSeconds ?? []);
|
|
}
|
|
|
|
/**
|
|
* 取到期时间
|
|
*/
|
|
public function getSeconds()
|
|
{
|
|
$seconds = MicroSecond::where('status', 1)
|
|
->get();
|
|
return $seconds->count() > 0 ? $this->success($seconds) : $this->error($seconds);
|
|
}
|
|
|
|
|
|
/**
|
|
* 獲取訂單結果
|
|
*/
|
|
public function getResult(Request $request) {
|
|
$id = $request->input('id', 0);
|
|
if ($id) {
|
|
$user_id = Users::getUserId();
|
|
$order = MicroOrder::where('user_id', $user_id)->where('id', $id)->first();
|
|
|
|
return $this->success($order);
|
|
}
|
|
return $this->error('ID is must.');
|
|
}
|
|
|
|
/**
|
|
* 下单
|
|
*
|
|
* @param Request $request
|
|
* @return \Illuminate\Http\JsonResponse
|
|
*/
|
|
public function submit(Request $request)
|
|
{
|
|
$user_id = Users::getUserId();
|
|
$type = $request->input('type', 0);
|
|
$match_id = $request->input('match_id', 0);
|
|
$currency_id = $request->input('currency_id', 0);
|
|
$seconds = $request->input('seconds', 0);
|
|
$number = $request->input('number', 0);
|
|
$validator = Validator::make($request->all(), [
|
|
'match_id' => 'required|integer|min:1',
|
|
'currency_id' => 'required|integer|min:1',
|
|
'type' => 'required|integer|in:1,2',
|
|
'seconds' => 'required|integer|min:1',
|
|
'number' => 'required|numeric|min:0',
|
|
], [], [
|
|
'match_id' => '交易对',
|
|
'currency_id' => '支付币种',
|
|
'type' => '下单类型',
|
|
'seconds' => '到期时间',
|
|
'number' => '投资数额',
|
|
]);
|
|
|
|
if(Cache::has("microtrade_$user_id")){
|
|
return $this->error('Do not repeat the operation!');
|
|
}
|
|
Cache::put("microtrade_$user_id", 1, Carbon::now()->addSeconds(1));//用户1秒只能点击一次
|
|
try {
|
|
//进行基本验证
|
|
throw_if($validator->fails(), new \Exception($validator->errors()->first()));
|
|
$insurance_start = Setting::getValueByKey('insurance_start','09:00');
|
|
$insurance_end = Setting::getValueByKey('insurance_end','12:00');
|
|
|
|
$insurance_start_datetime = Carbon::parse(date("Y-m-d {$insurance_start}:00"));
|
|
$insurance_end_datetime = Carbon::parse(date("Y-m-d {$insurance_end}:00"));
|
|
$use_insurance = 0;//是否使用受保金额
|
|
$currency = Currency::find($currency_id);
|
|
//在受保时间段的话
|
|
if (Carbon::now()->gte($insurance_start_datetime) && Carbon::now()->lte($insurance_end_datetime)) {
|
|
if($currency->insurancable == 1){
|
|
$can_order = $this->canOrder($user_id, $currency_id, $number);
|
|
if($can_order !== true){
|
|
throw new \Exception("下单失败:{$can_order}");
|
|
}
|
|
$user_insurance = UsersInsurance::where('user_id', $user_id)
|
|
->whereHas('insurance_type', function ($query) use ($currency_id) {
|
|
$query->where('currency_id', $currency_id);
|
|
})
|
|
->where('status', 1)
|
|
->where('claim_status', 0)
|
|
->first();
|
|
$use_insurance = $user_insurance->insurance_type->type;//1,正向。2,反向。
|
|
}
|
|
}
|
|
if (
|
|
($currency->insurancable != 1 || $use_insurance == 0) //如果当前不在受保时间段内或者所返币种不支持保险
|
|
&& $currency->micro_holdtrade_max > 0
|
|
&& $this->getExistingOrderNumber($user_id, $currency_id) >= $currency->micro_holdtrade_max
|
|
) {
|
|
throw new \Exception('下单失败:超过最大持仓笔数限制');
|
|
}
|
|
$currency_match = CurrencyMatch::find($match_id);
|
|
|
|
// $currency_quotation = CurrencyQuotation::where('match_id', $match_id)->first();
|
|
// $fluctuate_min = $currency_quotation->now_price * 0.0001;
|
|
// $fluctuate_max = $currency_quotation->now_price * 0.001;
|
|
// throw_unless($currency_quotation, new \Exception('当前未获取到行情'));
|
|
$market = MarketHour::getLastEsearchMarket($currency_match->currency_name, $currency_match->legal_name, '1min');
|
|
throw_unless($market, new \Exception('当前未获取到行情'));
|
|
// $rkey = 'market.'.strtolower($currency_match->currency_name. $currency_match->legal_name).'.kline.1min';
|
|
|
|
// $market = json_decode(Redis::get($rkey),true);//MarketHour::getLastEsearchMarket($currency_match->currency_name, $currency_match->legal_name, '1min');
|
|
// $market=$market['tick'];
|
|
//下单价格随机浮动,减少价格重复概率
|
|
$decimal = 0;
|
|
$faker = \Faker\Factory::create();
|
|
// if (stripos($currency_match->fluctuate_min, '.') !== false) {
|
|
// // $fluctuate_min = rtrim($fluctuate_min, '0'); //移除掉小数点后面右侧多余的0
|
|
// $fluctuate_min = rtrim($fluctuate_min, '.'); //如果是整数再移除掉小数点
|
|
// $decimal_index = stripos($fluctuate_min, '.'); //查找小数点的位置
|
|
// if ($decimal_index !== false) {
|
|
// $decimal = strlen($fluctuate_min) - $decimal_index - 1;
|
|
// }
|
|
// }
|
|
// trim($fluctuate_min, '0');
|
|
// var_dump($currency_match->fluctuate_min);exit;
|
|
// $float_diff = $faker->randomFloat($decimal, $fluctuate_min, $currency_match->fluctuate_max);
|
|
// $price = $market['close'] ?? $currency_quotation->now_price;
|
|
$price = $market['close'];
|
|
|
|
// if (mt_rand(0, 1)) {
|
|
// $price = bc_add($price, $float_diff);
|
|
// } else {
|
|
// $price = bc_sub($price, $float_diff);
|
|
// }
|
|
|
|
// var_dump($price);exit;
|
|
$order_data = [
|
|
'user_id' => $user_id,
|
|
'type' => $type,
|
|
'match_id' => $match_id,
|
|
'currency_id' => $currency_id,
|
|
'seconds' => $seconds,
|
|
'price' => $price,
|
|
'number' => $number,
|
|
'use_insurance' => $use_insurance,
|
|
];
|
|
$order = MicroTradeLogic::addOrder($order_data);
|
|
return $this->success($order);
|
|
} catch (\Throwable $th) {
|
|
// throw $th;
|
|
//return $this->error('File:' . $th->getFile() . ',Line:' . $th->getLine() . ',Message:' . $th->getMessage());
|
|
return $this->error($th->getMessage());
|
|
}
|
|
}
|
|
|
|
public function lists(Request $request)
|
|
{
|
|
try {
|
|
$user_id = Users::getUserId();
|
|
$limit = $request->input('limit', 10);
|
|
$status = $request->input('status', -1);
|
|
$match_id = $request->input('match_id', -1);
|
|
$currency_id = $request->input('currency_id', -1);
|
|
$lists = MicroOrder::where('user_id', $user_id)
|
|
->when($status <> -1, function ($query) use ($status) {
|
|
$query->where('status', $status);
|
|
})
|
|
->when($match_id <> -1, function ($query) use ($match_id) {
|
|
$query->where('match_id', $match_id);
|
|
})
|
|
->when($currency_id <> -1, function ($query) use ($currency_id) {
|
|
$query->where('currency_id', $currency_id);
|
|
})
|
|
->orderBy('id', 'desc')
|
|
->paginate($limit);
|
|
$lists->each(function ($item, $key) {
|
|
return $item->append('remain_milli_seconds');
|
|
});
|
|
/*
|
|
$results = $lists->getCollection();
|
|
$results->transform(function ($item, $key) {
|
|
return $item->append('remain_milli_seconds');
|
|
});
|
|
$lists->setCollection($results);
|
|
*/
|
|
return $this->success($lists);
|
|
} catch (\Throwable $th) {
|
|
return $this->error($th->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获得期权下单规则
|
|
*/
|
|
protected function getOrderRules($user_id, $currency_id, $user_insurance)
|
|
{
|
|
//默认规则
|
|
|
|
$insurance_rules_arr = $user_insurance->insurance_rules_arr;
|
|
if(count($insurance_rules_arr) > 0){
|
|
foreach ($insurance_rules_arr as $rule){
|
|
if($user_insurance->amount >= $rule['amount']){
|
|
return $rule;
|
|
}
|
|
}
|
|
}
|
|
return $rule = [
|
|
'place_an_order_max' => 500,
|
|
'existing_number' => 3
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获得该币种交易中的期权订单
|
|
*/
|
|
protected function getExistingOrderNumber($user_id, $currency_id){
|
|
$count = MicroOrder::where('user_id', $user_id)
|
|
->where('status', MicroOrder::STATUS_OPENED)
|
|
->where('currency_id', $currency_id)
|
|
->count();
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 受保时间段是否可以下单
|
|
*/
|
|
protected function canOrder($user_id, $currency_id, $number)
|
|
{
|
|
//$user = Users::getById($user_id);
|
|
//该币种是否购买了保险
|
|
$user_insurance = UsersInsurance::where('user_id', $user_id)
|
|
->whereHas('insurance_type', function ($query) use ($currency_id) {
|
|
$query->where('currency_id', $currency_id);
|
|
})
|
|
->where('status', 1)
|
|
->where('claim_status', 0)
|
|
->first();
|
|
if(!$user_insurance){
|
|
return '尚未申购或理赔保险';
|
|
}
|
|
$insurance_type = $user_insurance->insurance_type;
|
|
if($insurance_type->is_t_add_1 == 1){
|
|
$user_insurance_created_at_date = Carbon::parse($user_insurance->created_at);
|
|
if(Carbon::today()->isSameAs('Y-m-d',$user_insurance_created_at_date)){
|
|
return '申购的保险T+1生效';
|
|
}
|
|
}
|
|
|
|
//dd($insurance_type);
|
|
//该用户该保险的对应的钱包。
|
|
$user_wallet = UsersWallet::where('user_id', $user_id)
|
|
->where('currency', $insurance_type->currency_id)
|
|
->first();
|
|
|
|
//受保资产为0不允许下单
|
|
if($user_wallet->insurance_balance == 0){
|
|
return '受保资产为零';
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ($insurance_type->type){
|
|
case 1:
|
|
//受保金额小于等于此时不可以下单
|
|
$defective_amount = bc_mul($user_insurance->amount ,bc_div($insurance_type->defective_claims_condition, 100));
|
|
|
|
//正向险种,受保资产小于等于【条件1额度】,不允许下单
|
|
if($user_wallet->insurance_balance <= $defective_amount){
|
|
return '受保资产小于等于可下单条件';
|
|
}
|
|
break;
|
|
case 2:
|
|
//反向险种,受保资产小于等于【条件2额度】,不允许下单
|
|
if($user_wallet->insurance_balance <= $insurance_type->defective_claims_condition2){
|
|
return '您已超过持仓限制,暂停下单。';
|
|
}
|
|
break;
|
|
default:
|
|
return '未知的险种类型';
|
|
}
|
|
|
|
|
|
$order_rules = $this->getOrderRules($user_id, $currency_id, $user_insurance);
|
|
//dd($order_rules);
|
|
if($number > $order_rules['place_an_order_max']){
|
|
return '超过最大持仓数量限制';
|
|
}
|
|
|
|
$getExistingOrderNumber = $this->getExistingOrderNumber($user_id, $currency_id);
|
|
if($getExistingOrderNumber >= $order_rules['existing_number']){
|
|
return '交易中的订单大于最大挂单数量';
|
|
}
|
|
|
|
return true;//可以下单
|
|
}
|
|
|
|
|
|
}
|