<!DOCTYPE html>
|
<html>
|
<head>
|
<meta charset="utf-8">
|
<title>看盘端</title>
|
<link rel="stylesheet" type="text/css" href="./css/index23-05-04.css?_=1" />
|
<link rel="stylesheet" type="text/css" href="layui/css/layui.css" />
|
<script src="js/jquery.min.js"></script>
|
<script src="http://cdn.yeshitv.com/js/vue.min.js"></script>
|
<script src="layui/layui.js"></script>
|
<script src="js/kpl.js"></script>
|
<script src="js/vconsole.min.js"></script>
|
<script src="js/chart.js"></script>
|
<script src="js/chartjs-plugin-datalabels.min.js"></script>
|
<script src="js/md5.min.js"></script>
|
<style>
|
|
body{
|
max-width: none;
|
}
|
#app {
|
padding: 20px;
|
}
|
|
.label {
|
padding: 2px 5px;
|
border-radius: 3px;
|
margin: 5px;
|
background-color: #BBB;
|
}
|
|
.plate_codes_container {
|
max-width: 800px;
|
display: flex;
|
flex-wrap: wrap;
|
}
|
|
.plate_codes_container div {
|
width: 350px;
|
margin: 10px;
|
}
|
|
.big_orders_container {
|
max-width: 600px;
|
}
|
|
#app {
|
display: flex;
|
}
|
|
.space {
|
width: 10px;
|
display: inline-block;
|
}
|
|
.block-in-item {
|
background-color: #BBB;
|
border-radius: 5px;
|
padding: 5px;
|
margin: 0px 0px 5px 5px;
|
cursor: pointer;
|
}
|
|
.block-in-container {
|
display: flex;
|
flex-wrap: wrap;
|
|
}
|
|
red {
|
color: #FF0000;
|
}
|
.target-codes-container{
|
display: flex;
|
flex-wrap: wrap;
|
}
|
.target-codes-container div{
|
margin: 5px;
|
}
|
</style>
|
</head>
|
<body>
|
<div id="app">
|
<div style="width: 1000px;">
|
<form class="layui-form" action="">
|
<div class="layui-form-item">
|
<div class="layui-inline">
|
<input type="text" placeholder="日期" class="layui-input" lay-verify="required" name="date"
|
style="width: 100px;" />
|
</div>
|
<div class="layui-inline">
|
<input type="text" placeholder="时间" class="layui-input" lay-verify="required" name="time"
|
style="width: 100px;" />
|
</div>
|
|
<div
|
style="width: 2px;height: 38px; background-color: gray;display: inline-block;margin-bottom: -13px;margin-right: 10px;">
|
</div>
|
|
<div class="layui-inline">
|
<button class="layui-btn" lay-submit lay-filter="limit_up_data">拉取涨停数据</button>
|
</div>
|
<div class="space"></div>
|
<div class="layui-inline">
|
<input type="text" placeholder="代码" class="layui-input" name="code" style="width: 100px;" />
|
</div>
|
<div class="layui-inline">
|
<button class="layui-btn" lay-submit lay-filter="big_order_data">拉取大单数据</button>
|
</div>
|
<div class="layui-inline">
|
<button class="layui-btn" lay-submit lay-filter="block_in_data">拉取板块流入</button>
|
</div>
|
</div>
|
</form>
|
|
<hr class="layui-border-black">
|
<!-- 板块 -->
|
<div style="display: flex;flex-wrap: wrap;">
|
<div @click="get_plate_codes(item[0])" class="label" v-for="item in limit_up_plates">
|
{{item[0]}}&{{item[1]}}&{{item[2]}} <i class="layui-icon red"
|
@click="get_plate_target_codes(item[0])"></i>
|
</div>
|
</div>
|
|
<hr class="layui-border-black">
|
|
<div class="block-in-container" v-if="block_in_datas.length>0">
|
<div v-for="item in block_in_datas" class="block-in-item" @click="click_block_in($event)">
|
<input type="checkbox" v-bind:key="item[0]" /><br>
|
{{item[0]}}<br>{{item[1]}}
|
<input type="hidden" :value="item[0]" />
|
</div>
|
|
<button class="layui-btn" style="margin: 5px;"
|
@click="pull_same_block_codes_by_jx">拉取代码(精选)</button>
|
<button class="layui-btn" style="margin: 5px;"
|
@click="pull_block_codes_by_limit_up_count">拉取代码(涨停次数)</button>
|
</div>
|
|
</div>
|
|
<div style="flex-grow: 1;padding: 10px;min-width: 400px;max-width: 600px;">
|
<fieldset class="layui-elem-field">
|
<legend>目标代码</legend>
|
<div class="layui-field-box">
|
<div class="target-codes-container">
|
<div v-for="item in target_codes_info">
|
{{item[0]}}({{item[1]}})
|
</div>
|
</div>
|
<button class="layui-btn" v-if="!backtest_task_id" @click="start_backtest">回测代码</button>
|
<button class="layui-btn" v-else @click="stop_backtest">结束回测</button>
|
</div>
|
</fieldset>
|
|
<fieldset class="layui-elem-field">
|
<legend>回测结果</legend>
|
<div class="layui-field-box">
|
<div class="scroll-y">
|
<button class="layui-btn" @click="get_backtest_result">刷新结果</button>
|
<div v-if="backtest_task_id">
|
<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop">
|
</i>
|
<span>回测进度:{{task_progress}}%</span>
|
</div>
|
|
|
|
|
<table class="layui-table">
|
<thead>
|
<th>时间</th>
|
<th>代码</th>
|
<th>涨幅</th>
|
<th>是否买入</th>
|
<th>说明</th>
|
</thead>
|
|
<tbody>
|
<tr v-for="item in back_test_results" :class="{'red': item[3][0]}">
|
<td>{{item[0]}}</td>
|
<td>{{item[1]}}</td>
|
<td>{{item[2]}}%</td>
|
<td>{{item[3][0]?'是':'否'}}</td>
|
<td>
|
<span v-if="item[3][0]"> {{item[3][2]}} </span>
|
<span v-else> {{item[3][1]}} </span>
|
</td>
|
</tr>
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
</div>
|
</fieldset>
|
</div>
|
|
|
|
|
|
|
|
<!-- 大单 -->
|
|
<div id="dialog_plate_codes" style="display: none;">
|
<div class="plate_codes_container">
|
|
|
<div v-for="item in plate_codes">
|
<span v-if="item[6]" class="green">(炸)</span>
|
<span>{{item[1]}}({{item[0]}})-{{item[3]}}-{{item[4]}}-{{item[5]}}</span>
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="dialog_big_orders" style="display: none;">
|
<div class="big_orders_container">
|
|
<table>
|
<thead>
|
<th>订单号</th>
|
<th>开始时间</th>
|
<th>成交量</th>
|
<th>金额</th>
|
<th>成交均价</th>
|
<th>结束时间</th>
|
</thead>
|
<tbody>
|
<tr v-for="item in big_orders" :class="{'green':item[1]==1,'red':item[1]==0}">
|
<td>{{item[2][0]}}</td>
|
<td>
|
<span v-if="item[2].length>5">{{item[2][5]}}</span>
|
<span v-else>{{item[2][3]}}</span>
|
</td>
|
<td>{{item[2][1]/100}}手</td>
|
<td>{{(item[2][2]/10000).toFixed(1)}}万</td>
|
<td>{{(item[2][2]/item[2][1]).toFixed(2)}}</td>
|
<td>{{item[2][3]}}</td>
|
</tr>
|
|
|
</tbody>
|
|
</table>
|
</div>
|
|
</div>
|
|
<div id="dialog_same_block_codes" style="display: none;">
|
<div class="plate_codes_container">
|
<div v-for="item in same_block_codes">
|
{{item[0]}}
|
<span v-html="item[1]"></span>
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<script>
|
var http_util = {
|
get: function(path, params, callback) {
|
var url = "http://192.168.3.252:8000" + path;
|
if (params) {
|
url += "?";
|
for (key in params) {
|
url += key + "=" + encodeURIComponent(params[key]) + "&"
|
}
|
url = url.slice(0, -1);
|
}
|
$.ajax({
|
url: url,
|
type: 'GET',
|
dataType: 'json', // 预期返回的数据类型
|
crossDomain: true, // 明确声明跨域请求
|
success: callback,
|
error: function(xhr, status, error) {
|
console.error("错误:", status, error);
|
}
|
});
|
}
|
};
|
|
$(function() {
|
var app = new Vue({
|
el: '#app',
|
data: {
|
limit_up_plates: [],
|
plate_codes: [],
|
target_plate: '',
|
big_orders: [],
|
// 板块流入数据
|
block_in_datas: [],
|
checked_blocks: new Set(),
|
same_block_codes: [],
|
// 目标代码信息
|
target_codes_info: [],
|
backtest_task_id:'',
|
back_test_results: [],
|
task_progress:0,
|
task_result_interval:null
|
},
|
watch: {
|
plate_codes: function() {
|
setTimeout(function() {
|
layer.open({
|
title: app.target_plate,
|
type: 1,
|
content: $("#dialog_plate_codes"),
|
});
|
}, 100);
|
|
},
|
big_orders: function() {
|
setTimeout(function() {
|
layer.open({
|
title: $("input[name=code]").val(),
|
type: 1,
|
content: $("#dialog_big_orders"),
|
});
|
}, 100);
|
|
},
|
same_block_codes: function() {
|
setTimeout(function() {
|
layer.open({
|
title: '板块下的代码',
|
type: 1,
|
content: $("#dialog_same_block_codes"),
|
});
|
}, 100);
|
|
},
|
},
|
mounted: function() {
|
layui.use('laydate', function() {
|
var laydate = layui.laydate;
|
|
//执行一个laydate实例
|
laydate.render({
|
elem: 'input[name=date]', //指定元素
|
type: 'date'
|
});
|
laydate.render({
|
elem: 'input[name=time]', //指定元素
|
type: 'time',
|
value: '15:00:00'
|
});
|
layui.form.on("submit(limit_up_data)", function(res) {
|
console.log(res.field)
|
app.get_limit_up_plate_list(res.field.date);
|
return false
|
});
|
layui.form.on("submit(big_order_data)", function(res) {
|
if (!res.field.code) {
|
layer.msg("请填写代码")
|
return false;
|
}
|
app.get_big_order_list(res.field.code)
|
return false
|
});
|
layui.form.on("submit(block_in_data)", function(res) {
|
// if (!res.field.code) {
|
// layer.msg("请填写代码")
|
// return false;
|
// }
|
app.get_block_in_datas();
|
return false
|
});
|
|
|
});
|
|
},
|
methods: {
|
get_limit_up_plate_list: function(date) {
|
let index = layer.load(1);
|
app.limit_up_plates = [];
|
http_util.get("/get_limit_up_plate_list", {
|
"date": date,
|
"time": $("input[name=time]").val(),
|
}, function(res) {
|
layer.close(index);
|
if (res.code == 0) {
|
app.limit_up_plates = res.data
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
},
|
get_plate_codes: function(plate) {
|
let index = layer.load(1);
|
http_util.get("/get_plate_codes", {
|
"date": $("input[name=date]").val(),
|
"time": $("input[name=time]").val(),
|
"plate": plate
|
}, function(res) {
|
layer.close(index);
|
if (res.code == 0) {
|
app.target_plate = plate;
|
app.plate_codes = res.data;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
},
|
get_big_order_list: function(code) {
|
let index = layer.load(1)
|
http_util.get("/get_big_order_list", {
|
"date": $("input[name=date]").val(),
|
"code": code
|
}, function(res) {
|
layer.close(index);
|
if (res.code == 0) {
|
app.big_orders = res.data;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
},
|
get_plate_target_codes: function(plate) {
|
// 获取板块目标票
|
http_util.get("/get_plate_target_codes", {
|
"date": $("input[name=date]").val(),
|
"time": $("input[name=time]").val(),
|
"plate": plate
|
}, function(res) {
|
layer.close(index);
|
if (res.code == 0) {
|
app.big_orders = res.data;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
|
},
|
get_block_in_datas: function(code) {
|
// 获取板块流入数据
|
app.block_in_datas = [];
|
let index = layer.load(1)
|
http_util.get("/get_block_in_datas", {
|
"date": $("input[name=date]").val(),
|
"time": $("input[name=time]").val()
|
}, function(res) {
|
layer.close(index);
|
if (res.code == 0) {
|
app.block_in_datas = res.data;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
},
|
click_block_in: function(event) {
|
var checkbox = $(event.target).find("input[type=checkbox]");
|
if (checkbox.is(':checked')) {
|
checkbox.prop('checked', false);
|
} else {
|
checkbox.prop('checked', true);
|
}
|
},
|
pull_same_block_codes_by_jx: function() {
|
var fblocks = [];
|
$(".block-in-container").find("input[type=checkbox]").each(function(index, e) {
|
if ($(e).is(":checked")) {
|
fblocks.push($(e).parent().find("input[type=hidden]").val());
|
}
|
});
|
|
if (fblocks.length < 1) {
|
layer.msg("尚未选中板块");
|
return;
|
}
|
console.log("选中的板块", fblocks);
|
|
http_util.get("/get_codes_by_jx_plates", {
|
"date": $("input[name=date]").val(),
|
"time": $("input[name=time]").val(),
|
"plates": JSON.stringify(fblocks)
|
}, function(res) {
|
console.log("目标代码", res);
|
if (res.code == 0) {
|
app.same_block_codes = res.data;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
|
|
},
|
|
pull_block_codes_by_limit_up_count: function() {
|
var fblocks = [];
|
$(".block-in-container").find("input[type=checkbox]").each(function(index, e) {
|
if ($(e).is(":checked")) {
|
fblocks.push($(e).parent().find("input[type=hidden]").val());
|
}
|
});
|
|
if (fblocks.length < 1) {
|
layer.msg("尚未选中板块");
|
return;
|
}
|
console.log("选中的板块", fblocks);
|
let loading_index = layer.load(1)
|
http_util.get("/get_codes_by_limit_up_count", {
|
"date": $("input[name=date]").val(),
|
"time": $("input[name=time]").val(),
|
"plates": JSON.stringify(fblocks)
|
}, function(res) {
|
layer.close(loading_index)
|
console.log("目标代码", res);
|
if (res.code == 0) {
|
app.target_codes_info = res.data;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
},
|
|
get_backtest_result:function(){
|
if(!app.backtest_task_id){
|
layer.msg("没有正在运行的任务");
|
return;
|
}
|
http_util.get("/get_backtest_result", {
|
"task_id": app.backtest_task_id
|
}, function(res) {
|
console.log("目标代码", res);
|
if (res.code == 0) {
|
app.back_test_results = res.data.results;
|
if(res.data.finish){
|
app.stop_backtest();
|
|
}
|
app.task_progress = res.data.progress;
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
},
|
start_backtest:function(){
|
let loading_index = layer.load(1)
|
let codes = [];
|
app.target_codes_info.forEach(function(e){
|
codes.push(e[0])
|
});
|
http_util.get("/start_run_backtest", {
|
"date": $("input[name=date]").val(),
|
"codes": JSON.stringify(codes)
|
}, function(res) {
|
layer.close(loading_index)
|
if (res.code == 0) {
|
app.backtest_task_id = res.data.task_id;
|
app.task_result_interval = setInterval(()=>{
|
app.get_backtest_result();
|
}, 1000);
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
|
},
|
stop_backtest:function(){
|
|
http_util.get("/stop_run_backtest", {
|
"task_id": app.backtest_task_id
|
}, function(res) {
|
if (res.code == 0) {
|
app.backtest_task_id = '';
|
app.task_progress = 0;
|
if(app.task_result_interval){
|
clearInterval(app.task_result_interval);
|
}
|
layer.msg("结束成功")
|
} else {
|
layer.msg(res.msg);
|
}
|
});
|
|
}
|
|
|
|
}
|
});
|
});
|
</script>
|
|
</body>
|
</html>
|