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 = { |
module.exports = { |
||||
lintOnSave: false, |
lintOnSave: false, |
||||
configureWebpack: { |
configureWebpack: { |
||||
// Set up all the aliases we use in our app.
|
// Set up all the aliases we use in our app.
|
||||
resolve: { |
resolve: { |
||||
alias: { |
alias: { |
||||
'chart.js': 'chart.js/dist/Chart.js' |
"chart.js": "chart.js/dist/Chart.js" |
||||
} |
} |
||||
}, |
}, |
||||
plugins: [ |
plugins: [ |
||||
new webpack.optimize.LimitChunkCountPlugin({ |
new webpack.optimize.LimitChunkCountPlugin({ |
||||
maxChunks: 6 |
maxChunks: 6 |
||||
}) |
}) |
||||
] |
], |
||||
|
optimization: { |
||||
|
minimizer: [ |
||||
|
new UglifyJsPlugin({ |
||||
|
uglifyOptions: { |
||||
|
output: { |
||||
|
comments: false |
||||
|
}, |
||||
|
compress: { |
||||
|
drop_debugger: true, |
||||
|
drop_console: true |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
] |
||||
|
} |
||||
}, |
}, |
||||
pwa: { |
pwa: { |
||||
name: 'Vue Black Dashboard', |
name: "Vue Black Dashboard", |
||||
themeColor: '#344675', |
themeColor: "#344675", |
||||
msTileColor: '#344675', |
msTileColor: "#344675", |
||||
appleMobileWebAppCapable: 'yes', |
appleMobileWebAppCapable: "yes", |
||||
appleMobileWebAppStatusBarStyle: '#344675' |
appleMobileWebAppStatusBarStyle: "#344675" |
||||
}, |
}, |
||||
pluginOptions: { |
pluginOptions: { |
||||
i18n: { |
i18n: { |
||||
locale: 'en', |
locale: "en", |
||||
fallbackLocale: 'en', |
fallbackLocale: "en", |
||||
localeDir: 'locales', |
localeDir: "locales", |
||||
enableInSFC: false |
enableInSFC: false |
||||
} |
} |
||||
}, |
}, |
||||
css: { |
css: { |
||||
// Enable CSS source maps.
|
// Enable CSS source maps.
|
||||
sourceMap: process.env.NODE_ENV !== 'production' |
sourceMap: process.env.NODE_ENV !== "production" |
||||
} |
} |
||||
}; |
}; |
||||
|
Loading…
Reference in new issue