Browse Source

回测

master
lizhixin 4 years ago
parent
commit
8903983535
  1. 14
      src/App.vue
  2. 4
      src/main.js
  3. 54
      src/oldComponents/EchartTable/kLine.vue
  4. 22
      src/pages/ReCheck/OrderTable.vue
  5. 114
      src/pages/ReCheck/index.vue

14
src/App.vue

@ -27,6 +27,18 @@ export default {
<style lang="scss"> <style lang="scss">
.el-tabs__item { .el-tabs__item {
color: #C9CCD2; color: #c9ccd2 !important;
}
.el-tabs__active-bar {
background-color: #333d54 !important;
}
.select-danger.el-select .el-input input {
background-color: transparent;
border-width: 1px;
border-color: #2b3553;
color: #fd5d93;
}
.el-input {
background-color: transparent;
} }
</style> </style>

4
src/main.js

@ -29,7 +29,8 @@ import {
Option, Option,
Tabs, Tabs,
TabPane, TabPane,
Pagination Pagination,
DatePicker
} from "element-ui"; } from "element-ui";
import "element-ui/lib/theme-chalk/index.css"; import "element-ui/lib/theme-chalk/index.css";
import i18n from "./i18n"; import i18n from "./i18n";
@ -47,6 +48,7 @@ Vue.use(Option);
Vue.use(Tabs); Vue.use(Tabs);
Vue.use(TabPane); Vue.use(TabPane);
Vue.use(Pagination); Vue.use(Pagination);
Vue.use(DatePicker);
/* eslint-disable no-new */ /* eslint-disable no-new */
new Vue({ new Vue({
router, router,

54
src/oldComponents/EchartTable/kLine.vue

@ -12,7 +12,7 @@ import {
LegendComponent, LegendComponent,
DataZoomComponent, DataZoomComponent,
MarkLineComponent, MarkLineComponent,
MarkPointComponent, MarkPointComponent
} from "echarts/components"; } from "echarts/components";
import { CandlestickChart, LineChart } from "echarts/charts"; import { CandlestickChart, LineChart } from "echarts/charts";
@ -29,7 +29,7 @@ echarts.use([
MarkPointComponent, MarkPointComponent,
CandlestickChart, CandlestickChart,
LineChart, LineChart,
CanvasRenderer, CanvasRenderer
]); ]);
var upColor = "#FCE4E4"; var upColor = "#FCE4E4";
@ -45,8 +45,8 @@ export default {
type: Object, type: Object,
default: () => { default: () => {
return { sale: -1, buy: -1 }; return { sale: -1, buy: -1 };
}, }
}, }
}, },
watch: { watch: {
data(newVal, oldVal) { data(newVal, oldVal) {
@ -63,7 +63,7 @@ export default {
if (this.tempKeyPointArray && this.tempKeyPointArray[0]) { if (this.tempKeyPointArray && this.tempKeyPointArray[0]) {
if (newVal.buy && newVal.buy != -1) { if (newVal.buy && newVal.buy != -1) {
result = this.tempKeyPointArray.filter( result = this.tempKeyPointArray.filter(
(item) => item =>
item.name == "卖出Point" || item.name == "卖出Point" ||
(item.name == "买入Point" && (item.name == "买入Point" &&
(item.value == newVal.buy || item.value > newVal.buy)) (item.value == newVal.buy || item.value > newVal.buy))
@ -72,7 +72,7 @@ export default {
if (newVal.sale && newVal.sale != -1) { if (newVal.sale && newVal.sale != -1) {
let _r = !newVal.buy ? this.tempKeyPointArray : result; let _r = !newVal.buy ? this.tempKeyPointArray : result;
result = _r.filter( result = _r.filter(
(item) => item =>
item.name == "买入Point" || item.name == "买入Point" ||
(item.name == "卖出Point" && (item.name == "卖出Point" &&
(item.value == newVal.sale || item.value > newVal.sale)) (item.value == newVal.sale || item.value > newVal.sale))
@ -82,7 +82,7 @@ export default {
!newVal.buy && !newVal.sale ? this.tempKeyPointArray : result; !newVal.buy && !newVal.sale ? this.tempKeyPointArray : result;
this.options && this.chart.setOption(this.options); this.options && this.chart.setOption(this.options);
} }
}, }
}, },
data() { data() {
return { return {
@ -96,16 +96,16 @@ export default {
tooltip: { tooltip: {
trigger: "axis", trigger: "axis",
axisPointer: { axisPointer: {
type: "cross", type: "cross"
}, }
}, },
legend: { legend: {
data: ["时分K"], data: ["时分K"]
}, },
grid: { grid: {
left: "10%", left: "10%",
right: "10%", right: "10%",
bottom: "10%", bottom: "10%"
}, },
xAxis: { xAxis: {
type: "category", type: "category",
@ -116,27 +116,27 @@ export default {
splitLine: { show: false }, splitLine: { show: false },
splitNumber: 20, splitNumber: 20,
min: "dataMin", min: "dataMin",
max: "dataMax", max: "dataMax"
}, },
yAxis: { yAxis: {
scale: true, scale: true,
splitArea: { splitArea: {
show: true, show: true
}, }
}, },
dataZoom: [ dataZoom: [
{ {
type: "inside", type: "inside",
start: 50, start: 50,
end: 100, end: 100
}, },
{ {
show: true, show: true,
type: "slider", type: "slider",
top: "90%", top: "90%",
start: 50, start: 50,
end: 100, end: 100
}, }
], ],
series: [ series: [
{ {
@ -148,23 +148,23 @@ export default {
color: upColor, color: upColor,
color0: downColor, color0: downColor,
borderColor: upBorderColor, borderColor: upBorderColor,
borderColor0: downBorderColor, borderColor0: downBorderColor
}, },
markPoint: { markPoint: {
label: { label: {
normal: { normal: {
formatter: function(param) { formatter: function(param) {
return param != null ? Math.round(param.value) : ""; return param != null ? Math.round(param.value) : "";
}, }
}, }
}, },
data: [], data: []
// tooltip: { // tooltip: {
// formatter: function(param) { // formatter: function(param) {
// return param.name + "<br>" + (param.data.coord || ""); // return param.name + "<br>" + (param.data.coord || "");
// }, // },
// }, // },
}, }
// markLine: { // markLine: {
// symbol: ["none", "none"], // symbol: ["none", "none"],
// data: [ // data: [
@ -211,7 +211,7 @@ export default {
// }, // },
// ], // ],
// }, // },
}, }
// { // {
// name: "MA5", // name: "MA5",
// type: "line", // type: "line",
@ -248,8 +248,8 @@ export default {
// opacity: 0.5, // opacity: 0.5,
// }, // },
// }, // },
], ]
}, }
}; };
}, },
mounted() { mounted() {
@ -272,8 +272,8 @@ export default {
result.push(sum / dayCount); result.push(sum / dayCount);
} }
return result; return result;
}, }
}, }
}; };
</script> </script>

22
src/pages/ReCheck/OrderTable.vue

@ -13,13 +13,17 @@
<template slot="KLineId" slot-scope="item"> <template slot="KLineId" slot-scope="item">
<p> <p>
{{ {{
moment(item.row.item.PurchaseKLineId * 1000).format("YYYY-MM-DD HH:mm:ss") moment(item.row.item.PurchaseKLineId * 1000).format(
"YYYY-MM-DD HH:mm:ss"
)
}} }}
</p> </p>
<p> <p>
{{ {{
item.row.item.SaleKLineId item.row.item.SaleKLineId
? moment(item.row.item.SaleKLineId * 1000).format("YYYY-MM-DD HH:mm:ss") ? moment(item.row.item.SaleKLineId * 1000).format(
"YYYY-MM-DD HH:mm:ss"
)
: "-" : "-"
}} }}
</p> </p>
@ -43,7 +47,12 @@
<template slot="Profit" slot-scope="item"> <template slot="Profit" slot-scope="item">
<p>{{ item.row.item.Profit }}</p> <p>{{ item.row.item.Profit }}</p>
<p v-if="item.row.item.Profit"> <p v-if="item.row.item.Profit">
{{ ((item.row.item.Profit / item.row.item.TotalPurchasePrice) * 100).toFixed(2) }}% {{
(
(item.row.item.Profit / item.row.item.TotalPurchasePrice) *
100
).toFixed(2)
}}%
</p> </p>
<p v-else>-</p> <p v-else>-</p>
</template> </template>
@ -52,7 +61,10 @@
<p>{{ item.row.item.TotalProfit }}</p> <p>{{ item.row.item.TotalProfit }}</p>
<p v-if="item.row.item.TotalProfit"> <p v-if="item.row.item.TotalProfit">
{{ {{
((item.row.item.TotalProfit / policyFormData.PositionFund) * 100).toFixed(2) (
(item.row.item.TotalProfit / policyFormData.PositionFund) *
100
).toFixed(2)
}}% }}%
</p> </p>
<p v-else>-</p> <p v-else>-</p>
@ -67,7 +79,7 @@ import moment from "moment";
export default { export default {
model: { prop: "data", event: "tableDataChange" }, model: { prop: "data", event: "tableDataChange" },
props: { data: { type: Array, default: () => [] } }, props: { data: { type: Array, default: () => [] } },
components: CustomBaseTable, components: { CustomBaseTable },
data() { data() {
return { moment, columns: tradeColumns }; return { moment, columns: tradeColumns };
} }

114
src/pages/ReCheck/index.vue

@ -1,5 +1,55 @@
<template> <template>
<card> <card>
<div class="row">
<div class="col-md-6">
<div class="row">
<div class="col-md-3">
<base-button @click="excelImport">导入数据源</base-button>
</div>
<div class="col-md-4">
<base-input>
<el-date-picker
class="select-danger"
v-model="startTime"
type="datetime"
placeholder="选择开始日期与时间"
>
</el-date-picker>
</base-input>
</div>
<div class="col-md-4">
<base-input>
<el-date-picker
v-model="endTime"
type="datetime"
placeholder="选择结束日期与时间"
@change="timepIkcer"
>
</el-date-picker>
</base-input>
</div>
</div>
</div>
<div class="col-md-6">
<el-select
class="select-danger"
style="width:200px"
placeholder="策略选择"
v-model="policyMode"
>
<el-option
v-for="item in RobotPolicyType"
class="select-danger"
:label="item.title"
:key="item.value"
:value="item.value"
>
</el-option>
</el-select>
<base-button @click="executeTest" class="ml-2">执行回测</base-button>
<base-button class="ml-2">重置回测</base-button>
</div>
</div>
<!-- <a-row type="flex"> <!-- <a-row type="flex">
<a-col :span="16"> <a-col :span="16">
<a-row type="flex" <a-row type="flex"
@ -34,7 +84,7 @@
</a-row> --> </a-row> -->
<div> <div>
<el-tabs default-active-key="1"> <el-tabs value="1">
<el-tab-pane name="1" label="K线图表"> <el-tab-pane name="1" label="K线图表">
<div class="row"> <div class="row">
<div class="col-md-3"> <div class="col-md-3">
@ -101,13 +151,16 @@
<!-- <HQKline /> --> <!-- <HQKline /> -->
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="2" label="编译策略"> <el-tab-pane name="2" label="编译策略">
<MomentumWavePolicy v-if="policyMode == 0" v-model="policyFormData" /> <movement-policy-form
v-if="policyMode == 0"
v-model="policyFormData"
/>
<!-- <top-end-policy v-else v-model="policyFormData" /> --> <!-- <top-end-policy v-else v-model="policyFormData" /> -->
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<div> <div>
<el-tabs default-active-key="1"> <el-tabs value="1">
<!-- 交易清单 --> <!-- 交易清单 -->
<el-tab-pane name="1" label="交易清单"> <el-tab-pane name="1" label="交易清单">
<order-table v-model="tradeData"></order-table> <order-table v-model="tradeData"></order-table>
@ -116,15 +169,24 @@
<!-- 信号记录 --> <!-- 信号记录 -->
<el-tab-pane name="2" label="信号记录"> <el-tab-pane name="2" label="信号记录">
根据时间范围筛选信号记录 根据时间范围筛选信号记录
<a-range-picker <!-- <a-range-picker
style="margin: 10px 0" style="margin: 10px 0"
v-model="dateRange" v-model="dateRange"
:show-time="{ format: 'HH:mm' }" :show-time="{ format: 'HH:mm' }"
format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm"
:placeholder="['开始时间', '结束时间']" :placeholder="['开始时间', '结束时间']"
@ok="onOk" @change="onOk"
/> /> -->
<a-table <el-date-picker
v-model="dateRange"
type="datetimerange"
range-separator="~"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="onOk"
>
</el-date-picker>
<custom-base-table
size="small" size="small"
:columns="logColumns" :columns="logColumns"
:dataSource="logData.filter(logShowCondition)" :dataSource="logData.filter(logShowCondition)"
@ -132,7 +194,7 @@
<template slot="LogType" slot-scope="text"> <template slot="LogType" slot-scope="text">
{{ LogTypes.filter(item => item.value == text)[0].title }} {{ LogTypes.filter(item => item.value == text)[0].title }}
</template> </template>
</a-table> </custom-base-table>
</el-tab-pane> </el-tab-pane>
<!-- 绩效总结 --> <!-- 绩效总结 -->
<el-tab-pane name="3" label="绩效总结"> <el-tab-pane name="3" label="绩效总结">
@ -155,16 +217,18 @@ import {
ResetMomentumWaveTest, ResetMomentumWaveTest,
LogTypes LogTypes
} from "../prePages/js/selectoptions"; } from "../prePages/js/selectoptions";
import MomentumWavePolicy from "../../components/MovementPolicyForm"; import MovementPolicyForm from "../../components/MovementPolicyForm";
import moment from "moment"; import moment from "moment";
import OrderTable from "./OrderTable"; import OrderTable from "./OrderTable";
import CustomBaseTable from "../../components/CustomBaseTable.vue";
// import TopEndPolicy from "../components/TopEndPolicy.vue"; // import TopEndPolicy from "../components/TopEndPolicy.vue";
export default { export default {
components: { components: {
KLine, KLine,
AccountInfo, AccountInfo,
MomentumWavePolicy, MovementPolicyForm,
OrderTable OrderTable,
CustomBaseTable
// HQKline // HQKline
// TopEndPolicy // TopEndPolicy
@ -185,9 +249,9 @@ export default {
tradeData: [], tradeData: [],
startTime: null, startTime: null,
endTime: null, endTime: null,
kLineData: [], kLineData: {},
keyFilter: {}, keyFilter: {},
policyFormData: ResetMomentumWaveTest, policyFormData: {},
kLineDataList: [], kLineDataList: [],
dateRange: [], dateRange: [],
accountInfo: {}, accountInfo: {},
@ -197,10 +261,13 @@ export default {
logShowCondition: i => true logShowCondition: i => true
}; };
}, },
mounted() {
this.policyFormData = ResetMomentumWaveTest;
},
methods: { methods: {
onOk(value) { onOk(value) {
this.logShowCondition = item => this.logShowCondition = item =>
moment(item.CreateTime).isBetween(value[0], value[1]); moment(item.CreateTime).isBetween(moment(value[0]), moment(value[1]));
}, },
changeFilter(value, type) { changeFilter(value, type) {
console.log(value, type); console.log(value, type);
@ -411,16 +478,14 @@ export default {
this.startTime && this.startTime &&
this.endTime && this.endTime &&
!moment(data[i][j] * 1000).isBetween( !moment(data[i][j] * 1000).isBetween(
this.startTime.startOf("day"), moment(this.startTime),
this.endTime.endOf("day") moment(this.endTime)
) )
) { ) {
break; break;
} else if ( } else if (
this.startTime && this.startTime &&
!moment(data[i][j] * 1000).isAfter( !moment(data[i][j] * 1000).isAfter(moment(this.startTime))
this.startTime.startOf("day")
)
) { ) {
break; break;
} }
@ -615,10 +680,10 @@ export default {
console.log("回测成功"); console.log("回测成功");
this.logData = res.Data.ExecutionLogList; this.logData = res.Data.ExecutionLogList;
if (this.logData.length > 0) { if (this.logData.length > 0) {
this.dateRange[0] = moment( this.dateRange[0] = this.logData[
this.logData[this.logData.length - 1].CreateTime this.logData.length - 1
); ].CreateTime;
this.dateRange[1] = moment(this.logData[0].CreateTime); this.dateRange[1] = this.logData[0].CreateTime;
} }
res.Data.OrderList.sort( res.Data.OrderList.sort(
(a, b) => b.PurchaseKLineId - a.PurchaseKLineId (a, b) => b.PurchaseKLineId - a.PurchaseKLineId
@ -643,6 +708,9 @@ export default {
} }
}); });
} }
},
timepIkcer() {
console.log(this.startTime, this.endTime);
} }
} }
}; };

Loading…
Cancel
Save