BTCoinmt
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

411 lines
17 KiB

<?php
namespace App\Handlers;
use App\Models\TestTradeOrder;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Redis;
class Kline
{
/**** START ****/
// 后台生成一天的30分钟周期线 然后根据30分钟线随机生成1min线 机器人根据1minK线跑盘
private $klineData = [];
public function generateKline2($config, $end_time = null)
{
if (empty($config)) return false;
$datetime = $config['datetime'];
//Y-m-d H:i:s 开始结束时间
$start_date = Carbon::parse($datetime)->toDateTimeString();
$end_date = Carbon::parse($datetime)->addDays(1)->toDateTimeString();
if ($end_time) {
$end_date = Carbon::parse($end_time)->toDateTimeString();
}
// 生成K线
$this->fake_period_kline($config, $start_date, $end_date);
foreach ($this->klineData as &$kline) {
if ($kline['low'] < $config['low']) {
$kline['low'] = $config['low'];
}
if ($kline['high'] > $config['high']) {
$kline['high'] = $config['high'];
}
}
return $this->klineData;
}
// 生成30minK线
private function fake_period_kline($config, $start_date, $end_date)
{
$decimal = 100000;
$seconds = 1800;
$period = 'is_30min';
$open_price = $config['open'];
$close_price = $config['close'];
$high_price = $config['high'];
$low_price = $config['low'];
$min_amount = $config['min_amount'];
$max_amount = $config['max_amount'];
$start = strtotime($start_date);
$end = strtotime($end_date);
// dd($open_price,$close_price,$high_price,$low_price);
$period_seconds = 1800;
$periodCount = 86400 / $period_seconds;
$unit = custom_number_format(bcMath(($high_price - $low_price), $periodCount - 1, '/', 8), 8);
// 24小时 周期价格上涨下跌趋势随机 1涨2跌
$period2_seconds = 1800;
$periodCount2 = 86400 / $period2_seconds;
$periodsTrend = [];
for ($i = 0; $i < $periodCount2; $i++) {
if ($close_price > $open_price) {
$thresholdValue = 60;
} else {
$thresholdValue = 40;
}
$periodsTrend[$start + ($i * $period2_seconds)] = mt_rand(1, 100) <= $thresholdValue ? 1 : 2;
}
$ups_downs_high = abs(floor($unit * $decimal * 10)); //高
$ups_downs_value = abs(floor($unit * 5 * $decimal)); //值
$ups_downs_low = 0; //低
// dd($unit,$ups_downs_high,$ups_downs_value,$ups_downs_low);
$current = $start;
$kkk = 1;
while ($current < $end) {
// echo $current . '--' . $kkk . "\r\n";
// 获取上一条
$aa = Cache::get('klineData');
$prev_time = $current - $seconds;
$prev = array_first($this->klineData ?? [], function ($v, $k) use ($prev_time) {
return $v['timestamp'] == $prev_time;
});
if (blank($prev)) {
$price = $open_price * $decimal;
} else {
$price = $prev['close'] * $decimal;
}
$amount = mt_rand($min_amount * $decimal, $max_amount * $decimal) / $decimal;
$volume = bcMath($amount, $price, '/');
$open = $price;
$up_or_down = mt_rand(1, 100);
$flag = array_first($periodsTrend, function ($v, $k) use ($current, $period2_seconds) {
return $current >= $k && $current < ($k + $period2_seconds);
});
// dump($current . '--' . $flag);
if ($flag == 1) {
$value = 60;
} else {
$value = 40;
}
if($aa['close']>$high_price){
$up_or_down=100;
}else if($aa['close'] < $low_price){
$up_or_down=1;
}
// dump($ups_downs_low,$ups_downs_value,$ups_downs_high);
if ($up_or_down <= $value) {
// 涨
$close = mt_rand($price, $price + mt_rand($ups_downs_low, $ups_downs_high));
$high = mt_rand($close, $close + mt_rand($ups_downs_low, $ups_downs_value));
$low = mt_rand($close - mt_rand($ups_downs_low, $ups_downs_value), $close);
} else {
// 跌
$close = mt_rand($price - mt_rand($ups_downs_low, $ups_downs_high), $price);
$high = mt_rand($close, $close + mt_rand($ups_downs_value, $ups_downs_high));
$low = mt_rand($close - mt_rand($ups_downs_low, $ups_downs_value), $close);
}
if ($current == $start) {
$open = $open_price * $decimal;
} elseif ($current + $seconds == $end) {
$close = $close_price * $decimal;
}
$high = max($open, $close, $high, $low);
$low = min($open, $close, $high, $low);
$open = $open / $decimal;
$close = $close / $decimal;
$high = $high / $decimal;
$low = $low / $decimal;
// dd($open,$close,$high,$low,$prev->toArray());
$klineItem = [
'timestamp' => $current,
'datetime' => date('Y-m-d H:i:s', $current),
'open' => $open,
'close' => $close,
'high' => $high,
'low' => $low,
'volume' => $volume,
'amount' => $amount,
$period => 1,
];
array_push($this->klineData, $klineItem);
Cache::put("klineData", $klineItem);
$current += $seconds;
$kkk++;
}
return true;
}
/**** END ****/
//创建表
public function generateKline($period)
{
if ($period == '1min') {
$seconds = 60;
$open_carbon = Carbon::now()->floorMinute()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorMinute();
} elseif ($period == '5min') {
$seconds = 300;
$open_carbon = Carbon::now()->floorMinute()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorMinute();
} elseif ($period == '15min') {
$seconds = 900;
$open_carbon = Carbon::now()->floorMinute()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorMinute();
} elseif ($period == '30min') {
$seconds = 1800;
$open_carbon = Carbon::now()->floorMinute()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorMinute();
} elseif ($period == '60min') {
$seconds = 3600;
$open_carbon = Carbon::now()->floorHour()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorHour();
} elseif ($period == '4hour') {
$seconds = 14400;
$open_carbon = Carbon::now()->floorHour()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorHour();
} elseif ($period == '1day') {
$seconds = 86400;
$open_carbon = Carbon::now()->floorDay()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorDay();
} elseif ($period == '1week') {
$seconds = 604800;
$open_carbon = Carbon::now()->floorDay()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorDay();
} elseif ($period == '1mon') {
$seconds = 2592000;
$open_carbon = Carbon::now()->floorMonth()->subSeconds($seconds);
$close_carbon = Carbon::now()->floorMonth();
} else {
return;
}
$id = $close_carbon->timestamp;
$open_time = $open_carbon->timestamp;
$close_time = $close_carbon->timestamp;
$base_coin = 'lvo';
$quote_coin = 'usdt';
$table = strtolower("test_kline_" . $period . "_" . $base_coin . "_" . $quote_coin);
if (!Schema::hasTable($table)) {
$this->createTable($table);
}
$first = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->orderBy('order_id', 'asc')->first();
// if(blank($first)) return;
if (blank($first)) {
// 时间周期内没有数据
$prev = DB::table($table)->where('id', $open_time)->first(); // 上一条K线
if (blank($prev)) return;
$prev = get_object_vars($prev);
$data = [
"id" => $id,
"open" => $prev['open'],
"close" => (float)$prev['close'],
"high" => (float)$prev['high'],
"low" => (float)$prev['low'],
"price" => (float)$prev['price'],
"amount" => $prev['amount'],
"vol" => $prev['vol'],
"count" => $prev['count'],
"time" => time(),
];
} else {
$last = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->orderBy('order_id', 'desc')->first();
$high = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->max('unit_price');
$low = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->min('unit_price');
$amount = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->sum('trade_amount');
$count = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->count();
$vol = $amount * TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->avg('unit_price');
$prev = DB::table($table)->where('id', $open_time)->first(); // 上一条K线
if (blank($prev)) {
$open = (float)$first['unit_price'];
} else {
$prev = get_object_vars($prev);
$open = $prev['close'];
}
$data = [
"id" => $id,
"open" => $open,
"close" => (float)$last['unit_price'],
"high" => (float)$high,
"low" => (float)$low,
"price" => (float)$last['unit_price'],
"amount" => $amount,
"vol" => $vol,
"count" => $count,
"time" => time(),
];
}
// 缓存
Cache::store('redis')->put('market:' . $base_coin . $quote_coin . '_kline_' . $period, $data);
// 查询当前周期K线 防止重复插入
$kline = DB::table($table)->where('id', $id)->first();
if (blank($kline)) {
DB::table($table)->insert($data);
} else {
$kline->update(array_except($data, ['id']));
}
}
public function createTable($table)
{
Schema::create($table, function (Blueprint $table) {
$table->integer('id')->index()->default(0)->comment('时间周期');
$table->float('open', 20, 6)->default(0)->comment('开盘价');
$table->float('close', 20, 6)->default(0)->comment('收盘价');
$table->float('high', 20, 6)->default(0)->comment('最高价');
$table->float('low', 20, 6)->default(0)->comment('最低价');
$table->float('amount', 20, 6)->default(0)->comment('交易量(quote)');
$table->float('vol', 20, 6)->default(0)->comment('成交量(base)');
$table->float('price', 20, 6)->default(0)->comment('价格');
$table->integer('count')->default(0)->comment('成交单数');
$table->integer('time')->default(0)->comment('时间点记录');
});
}
public function cacheKline($period, $unit_price)
{
if ($period == '1min') {
$seconds = 60;
$open_carbon = Carbon::now()->floorMinute();
$close_carbon = Carbon::now()->floorMinute()->addSeconds($seconds);
} elseif ($period == '5min') {
$seconds = 300;
$open_carbon = Carbon::now()->floorMinute();
$close_carbon = Carbon::now()->floorMinute()->addSeconds($seconds);
} elseif ($period == '15min') {
$seconds = 900;
$open_carbon = Carbon::now()->floorMinute();
$close_carbon = Carbon::now()->floorMinute()->addSeconds($seconds);
} elseif ($period == '30min') {
$seconds = 1800;
$open_carbon = Carbon::now()->floorMinute();
$close_carbon = Carbon::now()->floorMinute()->addSeconds($seconds);
} elseif ($period == '60min') {
$seconds = 3600;
$open_carbon = Carbon::now()->floorHour();
$close_carbon = Carbon::now()->floorHour()->addSeconds($seconds);
} elseif ($period == '4hour') {
$seconds = 14400;
$open_carbon = Carbon::now()->floorHour();
$close_carbon = Carbon::now()->floorHour()->addSeconds($seconds);
} elseif ($period == '1day') {
$seconds = 86400;
$open_carbon = Carbon::now()->floorDay();
$close_carbon = Carbon::now()->floorDay()->addSeconds($seconds);
} elseif ($period == '1week') {
$seconds = 604800;
$open_carbon = Carbon::now()->floorDay();
$close_carbon = Carbon::now()->floorDay()->addSeconds($seconds);
} elseif ($period == '1mon') {
$seconds = 2592000;
$open_carbon = Carbon::now()->floorMonth();
$close_carbon = Carbon::now()->floorMonth()->addSeconds($seconds);
} else {
return;
}
$id = $open_carbon->timestamp;
$open_time = $open_carbon->timestamp;
$close_time = $close_carbon->timestamp;
$base_coin = 'lvo';
$quote_coin = 'usdt';
$table = strtolower("test_kline_" . $period . "_" . $base_coin . "_" . $quote_coin);
if (!Schema::hasTable($table)) {
$this->createTable($table);
}
$first = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->orderBy('order_id', 'asc')->first();
// if(blank($first)) return;
if (blank($first)) {
// 时间周期内没有数据
$prev = DB::table($table)->where('id', $open_time)->first(); // 上一条K线
if (blank($prev)) return;
$prev = get_object_vars($prev);
$data = [
"id" => $id,
"open" => $prev['open'],
"close" => (float)$unit_price,
"high" => (float)$prev['high'],
"low" => (float)$prev['low'],
"price" => (float)$prev['price'],
"amount" => $prev['amount'],
"vol" => $prev['vol'],
"count" => $prev['count'],
"time" => time(),
];
} else {
$high = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->max('unit_price');
$low = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->min('unit_price');
$amount = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->sum('trade_amount');
$count = TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->count();
$vol = $amount * TestTradeOrder::query()->whereBetween('ts', [$open_time, $close_time])->avg('unit_price');
$prev = DB::table($table)->where('id', $open_time)->first(); // 上一条K线
if (blank($prev)) {
$open = (float)$first['unit_price'];
} else {
$prev = get_object_vars($prev);
$open = $prev['close'];
}
$data = [
"id" => $id,
"open" => $open,
"close" => (float)$unit_price,
"high" => (float)$high,
"low" => (float)$low,
"price" => (float)$unit_price,
"amount" => $amount,
"vol" => $vol,
"count" => $count,
"time" => time(),
];
}
// 更新缓存
Cache::store('redis')->put('market:' . $base_coin . $quote_coin . '_kline_' . $period, $data);
}
}