10 changed files with 1130 additions and 77 deletions
@ -0,0 +1,74 @@ |
|||
<template> |
|||
<div> |
|||
<base-input |
|||
label=" 单轮趋势最大持仓金额" |
|||
v-model="accountInfo.MaxOrderTotalPurchasePricePerRound" |
|||
disabled |
|||
></base-input> |
|||
<base-input |
|||
label=" 单日持仓最大金额(当天内购买未在当天内出售)" |
|||
v-model="accountInfo.MaxTotalPurchasePricePerDay" |
|||
disabled |
|||
></base-input> |
|||
<base-input |
|||
label=" 订单持仓最长时间" |
|||
v-model="accountInfo.MaxTotalPurchasePricePerDay" |
|||
disabled |
|||
></base-input> |
|||
<p> |
|||
订单持仓最长时间:{{ |
|||
accountInfo.MaxOrderHoldTime && secToMin(accountInfo.MaxOrderHoldTime) |
|||
}} |
|||
</p> |
|||
|
|||
<p> |
|||
订单持仓最短时间:{{ |
|||
accountInfo.MinOrderHoldTime && secToMin(accountInfo.MinOrderHoldTime) |
|||
}} |
|||
</p> |
|||
|
|||
<p> |
|||
订单最大浮动亏损比:{{ |
|||
accountInfo.MaxOrderLossRatio && |
|||
accountInfo.MaxOrderLossRatio.toFixed(2) |
|||
}}% |
|||
</p> |
|||
|
|||
<p> |
|||
持仓最大浮动亏损比:{{ |
|||
accountInfo.MaxAccountLossRatio && |
|||
accountInfo.MaxAccountLossRatio.toFixed(2) |
|||
}}% |
|||
</p> |
|||
|
|||
<p> |
|||
最大盈利金额、订单盈利占比:{{ |
|||
accountInfo.MaxOrderProfit && accountInfo.MaxOrderProfit.toFixed(4) |
|||
}}({{ |
|||
accountInfo.MaxOrderProfitRatio && |
|||
accountInfo.MaxOrderProfitRatio.toFixed(2) |
|||
}}%) |
|||
</p> |
|||
|
|||
<p> |
|||
最小盈利金额、订单盈利占比:{{ |
|||
accountInfo.MinOrderProfit && accountInfo.MinOrderProfit.toFixed(4) |
|||
}}({{ |
|||
accountInfo.MinOrderProfitRatio && |
|||
accountInfo.MinOrderProfitRatio.toFixed(2) |
|||
}}%) |
|||
</p> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import { secToMin } from "../../utils/TimeUtils"; |
|||
export default { |
|||
model: { prop: "accountInfo", event: "accountChange" }, |
|||
props: { accountInfo: { type: Object, default: () => {} } }, |
|||
data() { |
|||
return { secToMin }; |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -0,0 +1,75 @@ |
|||
<template> |
|||
<custom-base-table |
|||
:data="data" |
|||
:columns="columns" |
|||
thead-classes="text-primary" |
|||
> |
|||
<!-- 卖卖类型 --> |
|||
<template slot="OrderType"> |
|||
<p>买入</p> |
|||
<p>卖出</p> |
|||
</template> |
|||
<!-- 买卖时间 --> |
|||
<template slot="KLineId" slot-scope="item"> |
|||
<p> |
|||
{{ |
|||
moment(item.row.item.PurchaseKLineId * 1000).format("YYYY-MM-DD HH:mm:ss") |
|||
}} |
|||
</p> |
|||
<p> |
|||
{{ |
|||
item.row.item.SaleKLineId |
|||
? moment(item.row.item.SaleKLineId * 1000).format("YYYY-MM-DD HH:mm:ss") |
|||
: "-" |
|||
}} |
|||
</p> |
|||
</template> |
|||
<!-- 买卖价格 --> |
|||
<template slot="Price" slot-scope="item"> |
|||
<p>{{ item.row.item.PurchasePrice || "-" }}</p> |
|||
<p>{{ item.row.item.SalePrice || "-" }}</p> |
|||
</template> |
|||
<!-- 买卖数量 --> |
|||
<template slot="Count" slot-scope="item"> |
|||
<p>{{ item.row.item.PurchaseCoinCount || "-" }}</p> |
|||
<p>{{ item.row.item.SaleCoinCount || "-" }}</p> |
|||
</template> |
|||
<!-- 最大浮亏 --> |
|||
<template slot="MaxLossRatio" slot-scope="item"> |
|||
<p>{{ item.row.item.MaxLossPrice || "-" }}</p> |
|||
<p>{{ item.row.item.MaxLossRatio || "-" }}%</p> |
|||
</template> |
|||
<!-- 盈亏 --> |
|||
<template slot="Profit" slot-scope="item"> |
|||
<p>{{ item.row.item.Profit }}</p> |
|||
<p v-if="item.row.item.Profit"> |
|||
{{ ((item.row.item.Profit / item.row.item.TotalPurchasePrice) * 100).toFixed(2) }}% |
|||
</p> |
|||
<p v-else>-</p> |
|||
</template> |
|||
<!-- 累计盈亏 --> |
|||
<template slot="TotalProfit" slot-scope="item"> |
|||
<p>{{ item.row.item.TotalProfit }}</p> |
|||
<p v-if="item.row.item.TotalProfit"> |
|||
{{ |
|||
((item.row.item.TotalProfit / policyFormData.PositionFund) * 100).toFixed(2) |
|||
}}% |
|||
</p> |
|||
<p v-else>-</p> |
|||
</template> |
|||
</custom-base-table> |
|||
</template> |
|||
|
|||
<script> |
|||
import CustomBaseTable from "../../components/CustomBaseTable"; |
|||
import { tradeColumns } from "../../pages/prePages/js/columns"; |
|||
import moment from "moment"; |
|||
export default { |
|||
model: { prop: "data", event: "tableDataChange" }, |
|||
props: { data: { type: Array, default: () => [] } }, |
|||
components: CustomBaseTable, |
|||
data() { |
|||
return { moment, columns: tradeColumns }; |
|||
} |
|||
}; |
|||
</script> |
@ -0,0 +1,651 @@ |
|||
<template> |
|||
<card> |
|||
<!-- <a-row type="flex"> |
|||
<a-col :span="16"> |
|||
<a-row type="flex" |
|||
><a-col><a-button @click="excelImport">导入数据源</a-button></a-col |
|||
><a-col :offset="1" |
|||
><a-date-picker v-model="startTime"></a-date-picker></a-col |
|||
><a-col :offset="1" |
|||
><a-date-picker v-model="endTime"></a-date-picker></a-col |
|||
><a-col :offset="1" |
|||
><a-select |
|||
v-model="policyMode" |
|||
placeholder="选择策略" |
|||
style="width:160px" |
|||
> |
|||
<a-select-option |
|||
v-for="i in RobotPolicyType" |
|||
:key="i.value" |
|||
:value="i.value" |
|||
> |
|||
{{ i.title }}</a-select-option |
|||
> |
|||
</a-select></a-col |
|||
> |
|||
</a-row></a-col |
|||
> |
|||
<a-col :span="4"> |
|||
<a-row type="flex"> |
|||
<a-col><a-button @click="executeTest">执行回测</a-button></a-col> |
|||
<a-col :offset="1"> <a-button>重置回测</a-button></a-col> |
|||
</a-row> |
|||
</a-col> |
|||
</a-row> --> |
|||
|
|||
<div> |
|||
<el-tabs default-active-key="1"> |
|||
<el-tab-pane name="1" label="K线图表"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<p class="form-label">文件列表</p> |
|||
<el-select |
|||
class="select-danger" |
|||
style="width:200px" |
|||
placeholder="不限" |
|||
v-model="lineSelect" |
|||
@change="onKlineExcelChange" |
|||
> |
|||
<el-option |
|||
v-for="item in kLinesFromExcels" |
|||
class="select-danger" |
|||
:label="item.name" |
|||
:key="item.name" |
|||
:value="item.name" |
|||
> |
|||
</el-option> |
|||
</el-select> |
|||
</div> |
|||
<div class="col-md-2"> |
|||
<p class="form-label">购买信号数显示过滤:</p> |
|||
<el-select |
|||
class="select-danger" |
|||
style="width:100px" |
|||
placeholder="不限" |
|||
v-model="keyFilter.buy" |
|||
@change="changeFilter($event, 1)" |
|||
> |
|||
<el-option |
|||
v-for="item in buyPointCountList" |
|||
class="select-danger" |
|||
:value="item.value" |
|||
:label="item.title" |
|||
:key="item.value" |
|||
> |
|||
</el-option> |
|||
</el-select> |
|||
</div> |
|||
<div class="col-md-2"> |
|||
<p class="form-label">卖出信号数显示过滤:</p> |
|||
<el-select |
|||
class="select-danger" |
|||
style="width:100px" |
|||
placeholder="不限" |
|||
v-model="keyFilter.sale" |
|||
@change="changeFilter($event, 0)" |
|||
> |
|||
<el-option |
|||
v-for="item in salePointCountList" |
|||
class="select-danger" |
|||
:value="item.value" |
|||
:label="item.title" |
|||
:key="item.value" |
|||
> |
|||
</el-option> |
|||
</el-select> |
|||
</div> |
|||
</div> |
|||
<!-- k线Excel选择 --> |
|||
|
|||
<KLine :data="kLineData" :keyFilter="keyFilter" /> |
|||
<!-- <HQKline /> --> |
|||
</el-tab-pane> |
|||
<el-tab-pane name="2" label="编译策略"> |
|||
<MomentumWavePolicy v-if="policyMode == 0" v-model="policyFormData" /> |
|||
<!-- <top-end-policy v-else v-model="policyFormData" /> --> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
</div> |
|||
<div> |
|||
<el-tabs default-active-key="1"> |
|||
<!-- 交易清单 --> |
|||
<el-tab-pane name="1" label="交易清单"> |
|||
<order-table v-model="tradeData"></order-table> |
|||
</el-tab-pane> |
|||
|
|||
<!-- 信号记录 --> |
|||
<el-tab-pane name="2" label="信号记录"> |
|||
根据时间范围筛选信号记录: |
|||
<a-range-picker |
|||
style="margin: 10px 0" |
|||
v-model="dateRange" |
|||
:show-time="{ format: 'HH:mm' }" |
|||
format="YYYY-MM-DD HH:mm" |
|||
:placeholder="['开始时间', '结束时间']" |
|||
@ok="onOk" |
|||
/> |
|||
<a-table |
|||
size="small" |
|||
:columns="logColumns" |
|||
:dataSource="logData.filter(logShowCondition)" |
|||
> |
|||
<template slot="LogType" slot-scope="text"> |
|||
{{ LogTypes.filter(item => item.value == text)[0].title }} |
|||
</template> |
|||
</a-table> |
|||
</el-tab-pane> |
|||
<!-- 绩效总结 --> |
|||
<el-tab-pane name="3" label="绩效总结"> |
|||
<account-info v-model="accountInfo" /> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
</div> |
|||
</card> |
|||
</template> |
|||
<script> |
|||
/* eslint-disable */ |
|||
import { tradeColumns, logColumns } from "../prePages/js/columns"; |
|||
import Excel from "../../utils/ExcelUtils"; |
|||
import KLine from "../../oldComponents/EchartTable/kLine"; |
|||
// import HQKline from "../../oldComponents/EchartTable/hqKline"; |
|||
import { secToMin } from "../../utils/TimeUtils"; |
|||
import AccountInfo from "./AccountInfo"; |
|||
import { |
|||
RobotPolicyType, |
|||
ResetMomentumWaveTest, |
|||
LogTypes |
|||
} from "../prePages/js/selectoptions"; |
|||
import MomentumWavePolicy from "../../components/MovementPolicyForm"; |
|||
import moment from "moment"; |
|||
import OrderTable from "./OrderTable"; |
|||
// import TopEndPolicy from "../components/TopEndPolicy.vue"; |
|||
export default { |
|||
components: { |
|||
KLine, |
|||
AccountInfo, |
|||
MomentumWavePolicy, |
|||
OrderTable |
|||
// HQKline |
|||
|
|||
// TopEndPolicy |
|||
}, |
|||
data() { |
|||
return { |
|||
moment, |
|||
secToMin, |
|||
LogTypes, |
|||
spinning: false, |
|||
lineSelect: "", |
|||
kLinesFromExcels: [], |
|||
tradeColumns, |
|||
logColumns, |
|||
logData: [], |
|||
RobotPolicyType, |
|||
policyMode: 0, |
|||
tradeData: [], |
|||
startTime: null, |
|||
endTime: null, |
|||
kLineData: [], |
|||
keyFilter: {}, |
|||
policyFormData: ResetMomentumWaveTest, |
|||
kLineDataList: [], |
|||
dateRange: [], |
|||
accountInfo: {}, |
|||
topTempDataList: [], |
|||
buyPointCountList: [], |
|||
salePointCountList: [], |
|||
logShowCondition: i => true |
|||
}; |
|||
}, |
|||
methods: { |
|||
onOk(value) { |
|||
this.logShowCondition = item => |
|||
moment(item.CreateTime).isBetween(value[0], value[1]); |
|||
}, |
|||
changeFilter(value, type) { |
|||
console.log(value, type); |
|||
this.keyFilter = Object.assign({}, this.keyFilter); |
|||
}, |
|||
splitData(rawData) { |
|||
var categoryData = []; |
|||
var keyPoint = []; |
|||
var values = []; |
|||
this.buyPointCountList = []; |
|||
this.salePointCountList = []; |
|||
|
|||
for (var i = 0; i < rawData.length; i++) { |
|||
categoryData.push(rawData[i].splice(0, 1)[0]); |
|||
let buyKey = rawData[i].splice(4, 1)[0]; |
|||
|
|||
if (buyKey && JSON.stringify(buyKey) != "{}") { |
|||
keyPoint.push(buyKey); |
|||
if (!this.buyPointCountList.some(item => item.value == buyKey.value)) |
|||
this.buyPointCountList.push(buyKey); |
|||
} |
|||
|
|||
let saleKey = rawData[i].splice(4, 1)[0]; |
|||
if (saleKey && JSON.stringify(saleKey) != "{}") { |
|||
keyPoint.push(saleKey); |
|||
if ( |
|||
!this.salePointCountList.some(item => item.value == saleKey.value) |
|||
) |
|||
this.salePointCountList.push(saleKey); |
|||
} |
|||
|
|||
values.push(rawData[i]); |
|||
} |
|||
console.log({ |
|||
categoryData, |
|||
values, |
|||
keyPoint |
|||
}); |
|||
return { |
|||
categoryData, |
|||
values, |
|||
keyPoint |
|||
}; |
|||
}, |
|||
//选择不同的excel表展示 |
|||
onKlineExcelChange(model) { |
|||
console.log(model); |
|||
if ( |
|||
this.kLinesFromExcels && |
|||
this.kLinesFromExcels.length > 0 && |
|||
this.kLinesFromExcels.some(item => item.name == model) |
|||
) { |
|||
let result = []; |
|||
if (this.policyMode == 0) { |
|||
let data = this.kLinesFromExcels.filter(item => item.name == model)[0] |
|||
.data; |
|||
let temp = this.mutateData(data); //分别操作出接口需要的data和图标data |
|||
result = this.splitData(temp.kLineData); //图表data处理 |
|||
this.kLineDataList = temp.postData; |
|||
this.kLineData = result; |
|||
} else { |
|||
let index = 0; |
|||
for (let i = 0; i < this.kLinesFromExcels.length; i++) { |
|||
if (this.kLinesFromExcels[i].name == model) { |
|||
index = i; |
|||
break; |
|||
} |
|||
} |
|||
let temp = this.topMutateData(this.topTempDataList[index]); |
|||
result = this.splitData(temp.kLineData); //图表data处理 |
|||
this.kLineData = result; |
|||
} |
|||
} |
|||
}, |
|||
excelImport() { |
|||
let that = this; |
|||
let result = []; |
|||
this.spinning = true; |
|||
Excel.importExcel(data => { |
|||
that.spinning = false; |
|||
if (data && data[0]) { |
|||
if (this.policyMode == 1) { |
|||
this.kLinesFromExcels = data; |
|||
this.lineSelect = data[0].name; |
|||
let _data = []; |
|||
data.forEach(element => { |
|||
_data.push(element.data); |
|||
}); |
|||
this.topEndMutateData(_data); |
|||
console.log("final", _data); |
|||
this.topTempDataList = _data; |
|||
let temp = that.topMutateData(_data[0]); |
|||
result = this.splitData(temp.kLineData); //图表data处理 |
|||
this.kLineData = result; |
|||
} else { |
|||
this.kLinesFromExcels = data; |
|||
this.lineSelect = data[0].name; |
|||
let temp = that.mutateData(data[0].data); //分别操作出接口需要的data和图标data |
|||
result = this.splitData(temp.kLineData); //图表data处理 |
|||
console.log("what i got", result); |
|||
this.kLineDataList = temp.postData; |
|||
this.kLineData = result; |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
//顶底策略数据处理 |
|||
topEndMutateData(data) { |
|||
if (data && data[0]) { |
|||
let originalArray = data[0]; |
|||
var offset = []; |
|||
for (let oi = 1; oi < originalArray.length; oi++) { |
|||
let target = originalArray[oi]; |
|||
var redTotal = target[5] == 1 ? 1 : 0; //以首表Red[5]为初始值 |
|||
var greenTotal = target[6] == 1 ? 1 : 0; |
|||
// console.log( |
|||
// "为时间戳:" + target[0] + "找匹配", |
|||
// " redTotal:" + redTotal |
|||
// ); |
|||
for (let di = 1; di < data.length; di++) { |
|||
let r = this.getOffset( |
|||
offset, |
|||
target, |
|||
data, |
|||
oi, |
|||
di, |
|||
redTotal, |
|||
greenTotal |
|||
); |
|||
if (r && r.redTotal) redTotal = r.redTotal; |
|||
if (r && r.greenTotal) greenTotal = r.greenTotal; |
|||
} |
|||
target[7] = target[5] == 1 ? redTotal : 0; |
|||
target[8] = target[6] == 1 ? greenTotal : 0; |
|||
for (let tempIndex = 1; tempIndex < data.length; tempIndex++) { |
|||
if (data[tempIndex][oi + offset[tempIndex]]) { |
|||
let condition = data[tempIndex][oi + offset[tempIndex]][5] == 1; |
|||
data[tempIndex][oi + offset[tempIndex]][7] = condition |
|||
? redTotal |
|||
: 0; |
|||
|
|||
let condition2 = data[tempIndex][oi + offset[tempIndex]][6] == 1; |
|||
data[tempIndex][oi + offset[tempIndex]][8] = condition2 |
|||
? greenTotal |
|||
: 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
//得出offset计算 |
|||
getOffset(offset, target, source, tIndex, sIndex, redTotal, greenTotal) { |
|||
// console.log(offset); |
|||
if (offset[sIndex] == null || offset[sIndex] == undefined) |
|||
offset[sIndex] = 0; |
|||
// console.log(target[0], source[sIndex][tIndex + offset[sIndex]][0]); |
|||
//先判读同个索引是否对其有对应时间戳 |
|||
if (!source[sIndex][tIndex + offset[sIndex]]) return; |
|||
if (target[0] == source[sIndex][tIndex + offset[sIndex]][0]) { |
|||
//相同索引有时间戳的 |
|||
redTotal = |
|||
redTotal + (source[sIndex][tIndex + offset[sIndex]][5] == 1 ? 1 : 0); |
|||
greenTotal = |
|||
greenTotal + |
|||
(source[sIndex][tIndex + offset[sIndex]][6] == 1 ? 1 : 0); |
|||
// console.log( |
|||
// target[0], |
|||
// redTotal, |
|||
// source[sIndex][tIndex + offset[sIndex]][0], |
|||
// "找到相等的" |
|||
// ); |
|||
return { redTotal, greenTotal }; |
|||
} else if (target[0] > source[sIndex][tIndex + offset[sIndex]][0]) { |
|||
// console.log("目标大", offset[sIndex]); |
|||
//目标时间戳大于比对的时间戳 |
|||
offset[sIndex] = offset[sIndex] + 1; |
|||
this.getOffset( |
|||
offset, |
|||
target, |
|||
source, |
|||
tIndex, |
|||
sIndex, |
|||
redTotal, |
|||
greenTotal |
|||
); |
|||
} else if (target[0] < source[sIndex][tIndex + offset[sIndex]][0]) { |
|||
offset[sIndex] = offset[sIndex] - 1; |
|||
// console.log("目标小", offset); |
|||
//目标时间戳小于比对的时间戳 |
|||
return; |
|||
} |
|||
}, |
|||
|
|||
//动量回测数据处理 |
|||
mutateData(data) { |
|||
let result = []; |
|||
let postResult = []; |
|||
if (data.length > 1) { |
|||
for (let i = 0; i < data.length; i++) { |
|||
if (i == 0) continue; |
|||
let subArray = []; |
|||
let postObj = { N: null }; |
|||
for (let j = 0; j < data[i].length; j++) { |
|||
if (j == 0) { |
|||
if ( |
|||
this.startTime && |
|||
this.endTime && |
|||
!moment(data[i][j] * 1000).isBetween( |
|||
this.startTime.startOf("day"), |
|||
this.endTime.endOf("day") |
|||
) |
|||
) { |
|||
break; |
|||
} else if ( |
|||
this.startTime && |
|||
!moment(data[i][j] * 1000).isAfter( |
|||
this.startTime.startOf("day") |
|||
) |
|||
) { |
|||
break; |
|||
} |
|||
|
|||
subArray[0] = moment(data[i][j] * 1000).format( |
|||
"YYYY-MM-DD HH:mm:ss" |
|||
); |
|||
postObj.T = data[i][j]; |
|||
} else if (j == 1) { |
|||
//open |
|||
subArray[1] = data[i][j]; |
|||
postObj.O = data[i][j]; |
|||
} else if (j == 2) { |
|||
//highest |
|||
subArray[4] = data[i][j]; |
|||
postObj.H = data[i][j]; |
|||
} else if (j == 3) { |
|||
//lowest |
|||
subArray[3] = data[i][j]; |
|||
postObj.L = data[i][j]; |
|||
} else if (j == 4) { |
|||
//close |
|||
subArray[2] = data[i][j]; |
|||
postObj.C = data[i][j]; |
|||
} else if (j == 7) { |
|||
postObj.TP = data[i][j]; |
|||
} else if (j == 13) { |
|||
if (data[i][j] != 0) postObj.N = 3; |
|||
} else if (j == 11) { |
|||
if (data[i][j] != 0) postObj.N = 2; |
|||
} else if (j == 15) { |
|||
subArray[5] = {}; |
|||
if (data[i][j] != 0) { |
|||
postObj.N = 1; |
|||
subArray[5] = { |
|||
name: "卖出Point", |
|||
coord: [ |
|||
`${moment(data[i][0] * 1000).format( |
|||
"YYYY-MM-DD HH:mm:ss" |
|||
)}`, |
|||
data[i][2] |
|||
], |
|||
value: "1", |
|||
itemStyle: { |
|||
color: "rgb(23,160,93)" |
|||
} |
|||
}; |
|||
} |
|||
} else if (j == 14) { |
|||
subArray[6] = {}; |
|||
if (data[i][j] != 0) { |
|||
postObj.N = 0; |
|||
subArray[6] = { |
|||
name: "买入Point", |
|||
symbol: "diamond", |
|||
symbolSize: [15, 25], |
|||
symbolOffset: [0, 25], |
|||
coord: [ |
|||
`${moment(data[i][0] * 1000).format( |
|||
"YYYY-MM-DD HH:mm:ss" |
|||
)}`, |
|||
data[i][3] |
|||
], |
|||
value: "0", |
|||
itemStyle: { |
|||
color: "rgb(221,82,70)" |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
if (subArray.length > 0) result.push(subArray); |
|||
if (postObj.T != null) postResult.push(postObj); |
|||
} |
|||
} |
|||
return { kLineData: result, postData: postResult }; |
|||
}, |
|||
|
|||
//订底回测数据处理 |
|||
topMutateData(data) { |
|||
let result = []; |
|||
let postResult = []; |
|||
if (data.length > 1) { |
|||
for (let i = 0; i < data.length; i++) { |
|||
if (i == 0) continue; |
|||
let subArray = []; |
|||
let postObj = { N: null }; |
|||
for (let j = 0; j < data[i].length; j++) { |
|||
if (j == 0) { |
|||
if ( |
|||
this.startTime && |
|||
this.endTime && |
|||
!moment(data[i][j] * 1000).isBetween( |
|||
this.startTime.startOf("day"), |
|||
this.endTime.endOf("day") |
|||
) |
|||
) { |
|||
break; |
|||
} else if ( |
|||
this.startTime && |
|||
!moment(data[i][j] * 1000).isAfter( |
|||
this.startTime.startOf("day") |
|||
) |
|||
) { |
|||
break; |
|||
} |
|||
|
|||
subArray[0] = moment(data[i][j] * 1000).format( |
|||
"YYYY-MM-DD HH:mm:ss" |
|||
); |
|||
postObj.T = data[i][j]; |
|||
} else if (j == 1) { |
|||
//open |
|||
subArray[1] = data[i][j]; |
|||
postObj.OpenPrice = data[i][j]; |
|||
} else if (j == 2) { |
|||
//highest |
|||
subArray[4] = data[i][j]; |
|||
postObj.H = data[i][j]; |
|||
} else if (j == 3) { |
|||
//lowest |
|||
subArray[3] = data[i][j]; |
|||
postObj.L = data[i][j]; |
|||
} else if (j == 4) { |
|||
//close |
|||
subArray[2] = data[i][j]; |
|||
postObj.C = data[i][j]; |
|||
} else if (j == 5) { |
|||
postObj.TP = data[i][j]; |
|||
} else if (j == 6) { |
|||
if (data[i][j] != 0) postObj.N = 3; |
|||
} else if (j == 7) { |
|||
subArray[5] = {}; |
|||
if (data[i][j] && data[i][j] != 0) { |
|||
postObj.N = 1; |
|||
subArray[5] = { |
|||
name: "买入Point", |
|||
coord: [ |
|||
`${moment(data[i][0] * 1000).format( |
|||
"YYYY-MM-DD HH:mm:ss" |
|||
)}`, |
|||
data[i][3] |
|||
], |
|||
value: data[i][j], |
|||
itemStyle: { |
|||
color: "rgb(23,160,93)" |
|||
} |
|||
}; |
|||
} |
|||
} else if (j == 8) { |
|||
subArray[6] = {}; |
|||
if (data[i][j] && data[i][j] != 0) { |
|||
postObj.N = 0; |
|||
subArray[6] = { |
|||
name: "卖出Point", |
|||
symbol: "diamond", |
|||
symbolSize: [15, 25], |
|||
symbolOffset: [0, 25], |
|||
coord: [ |
|||
`${moment(data[i][0] * 1000).format( |
|||
"YYYY-MM-DD HH:mm:ss" |
|||
)}`, |
|||
data[i][2] |
|||
], |
|||
value: data[i][j], |
|||
itemStyle: { |
|||
color: "rgb(221,82,70)" |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
if (subArray.length > 0) result.push(subArray); |
|||
if (postObj.T != null) postResult.push(postObj); |
|||
} |
|||
} |
|||
return { kLineData: result, postData: postResult }; |
|||
}, |
|||
|
|||
executeTest() { |
|||
if (this.policyFormData && this.kLineDataList.length > 0) { |
|||
this.spinning = true; |
|||
this.$http |
|||
.post("/Api/Simulation/MomentumWaveTest", { |
|||
MomentumWavePolicy: this.policyFormData, |
|||
kLineDataList: this.kLineDataList |
|||
}) |
|||
.then(res => { |
|||
this.logShowCondition = i => true; |
|||
this.spinning = false; |
|||
if (res.Code == 200) { |
|||
console.log("回测成功"); |
|||
this.logData = res.Data.ExecutionLogList; |
|||
if (this.logData.length > 0) { |
|||
this.dateRange[0] = moment( |
|||
this.logData[this.logData.length - 1].CreateTime |
|||
); |
|||
this.dateRange[1] = moment(this.logData[0].CreateTime); |
|||
} |
|||
res.Data.OrderList.sort( |
|||
(a, b) => b.PurchaseKLineId - a.PurchaseKLineId |
|||
); |
|||
this.tradeData = res.Data.OrderList; |
|||
//accountInfo |
|||
this.accountInfo.MaxOrderTotalPurchasePricePerRound = |
|||
res.Data.MaxOrderTotalPurchasePricePerRound; |
|||
this.accountInfo.MaxTotalPurchasePricePerDay = |
|||
res.Data.MaxTotalPurchasePricePerDay; |
|||
this.accountInfo.MaxOrderHoldTime = res.Data.MaxOrderHoldTime; |
|||
this.accountInfo.MinOrderHoldTime = res.Data.MinOrderHoldTime; |
|||
this.accountInfo.MaxOrderLossRatio = res.Data.MaxOrderLossRatio; |
|||
this.accountInfo.MaxAccountLossRatio = |
|||
res.Data.MaxAccountLossRatio; |
|||
this.accountInfo.MaxOrderProfit = res.Data.MaxOrderProfit; |
|||
this.accountInfo.MaxOrderProfitRatio = |
|||
res.Data.MaxOrderProfitRatio; |
|||
this.accountInfo.MinOrderProfit = res.Data.MinOrderProfit; |
|||
this.accountInfo.MinOrderProfitRatio = |
|||
res.Data.MinOrderProfitRatio; |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -1,37 +1,52 @@ |
|||
const webpack = require('webpack'); |
|||
|
|||
const webpack = require("webpack"); |
|||
const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); |
|||
module.exports = { |
|||
lintOnSave: false, |
|||
configureWebpack: { |
|||
// Set up all the aliases we use in our app.
|
|||
resolve: { |
|||
alias: { |
|||
'chart.js': 'chart.js/dist/Chart.js' |
|||
"chart.js": "chart.js/dist/Chart.js" |
|||
} |
|||
}, |
|||
plugins: [ |
|||
new webpack.optimize.LimitChunkCountPlugin({ |
|||
maxChunks: 6 |
|||
}) |
|||
] |
|||
], |
|||
optimization: { |
|||
minimizer: [ |
|||
new UglifyJsPlugin({ |
|||
uglifyOptions: { |
|||
output: { |
|||
comments: false |
|||
}, |
|||
compress: { |
|||
drop_debugger: true, |
|||
drop_console: true |
|||
} |
|||
} |
|||
}) |
|||
] |
|||
} |
|||
}, |
|||
pwa: { |
|||
name: 'Vue Black Dashboard', |
|||
themeColor: '#344675', |
|||
msTileColor: '#344675', |
|||
appleMobileWebAppCapable: 'yes', |
|||
appleMobileWebAppStatusBarStyle: '#344675' |
|||
name: "Vue Black Dashboard", |
|||
themeColor: "#344675", |
|||
msTileColor: "#344675", |
|||
appleMobileWebAppCapable: "yes", |
|||
appleMobileWebAppStatusBarStyle: "#344675" |
|||
}, |
|||
pluginOptions: { |
|||
i18n: { |
|||
locale: 'en', |
|||
fallbackLocale: 'en', |
|||
localeDir: 'locales', |
|||
locale: "en", |
|||
fallbackLocale: "en", |
|||
localeDir: "locales", |
|||
enableInSFC: false |
|||
} |
|||
}, |
|||
css: { |
|||
// Enable CSS source maps.
|
|||
sourceMap: process.env.NODE_ENV !== 'production' |
|||
sourceMap: process.env.NODE_ENV !== "production" |
|||
} |
|||
}; |
|||
|
Loading…
Reference in new issue