add create strategy dialog
This commit is contained in:
+21
-3
@@ -10,6 +10,14 @@ const get_strategy_files = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"strategy file list"
|
||||||
|
const get_strategy_load_files = () => {
|
||||||
|
return trader_service({
|
||||||
|
url: '/trader/api/v1/strategy_file/load',
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
"upload a strategy file"
|
"upload a strategy file"
|
||||||
const upload_strategy_file = (file: any) => {
|
const upload_strategy_file = (file: any) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
@@ -58,11 +66,11 @@ const get_strategies = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"create a strategy"
|
"create a strategy"
|
||||||
const create_strategy = () => {
|
const create_strategy = (ruleForm: object) => {
|
||||||
return trader_service({
|
return trader_service({
|
||||||
url: '/trader/api/v1/strategy',
|
url: '/trader/api/v1/strategy',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {}
|
data: ruleForm
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +106,17 @@ const get_strategy_status = (strategy_name: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"get a strategy status"
|
||||||
|
const get_vt_symbols = () => {
|
||||||
|
return trader_service({
|
||||||
|
url: '/trader/api/v1/strategy/vt_symbols',
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
get_strategy_files,
|
get_strategy_files,
|
||||||
|
get_strategy_load_files,
|
||||||
upload_strategy_file,
|
upload_strategy_file,
|
||||||
load_strategy_file,
|
load_strategy_file,
|
||||||
unload_strategy_file,
|
unload_strategy_file,
|
||||||
@@ -109,5 +126,6 @@ export {
|
|||||||
start_strategy,
|
start_strategy,
|
||||||
stop_strategy,
|
stop_strategy,
|
||||||
remove_strategy,
|
remove_strategy,
|
||||||
get_strategy_status
|
get_strategy_status,
|
||||||
|
get_vt_symbols
|
||||||
}
|
}
|
||||||
+9
-9
@@ -61,25 +61,25 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: '一键打包'
|
name: '一键打包'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
path: '/trader',
|
// path: '/trader',
|
||||||
component: () => import('../view/trader/index.vue'),
|
// component: () => import('../view/trader/index.vue'),
|
||||||
meta: {
|
// meta: {
|
||||||
name: 'trader'
|
// name: 'trader'
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
path: '/strategy',
|
path: '/strategy',
|
||||||
component: () => import('../view/trader/cta_strategy_file.vue'),
|
component: () => import('../view/trader/cta_strategy_file.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
name: '策略文件管理'
|
name: '策略文件'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/strategy_instance',
|
path: '/strategy_instance',
|
||||||
component: () => import('../view/trader/cta_strategy.vue'),
|
component: () => import('../view/trader/cta_strategy.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
name: '策略管理'
|
name: 'CTA策略'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { acceptHMRUpdate, defineStore } from "pinia"
|
||||||
|
|
||||||
|
export const strategyStore = defineStore({
|
||||||
|
id: 'strategy',
|
||||||
|
state: () => ({
|
||||||
|
class_names: [],
|
||||||
|
vt_symbols: []
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (import.meta.hot) {
|
||||||
|
import.meta.hot.accept(acceptHMRUpdate(strategyStore, import.meta.hot))
|
||||||
|
}
|
||||||
@@ -1,19 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bookmark">
|
<div class="startegy">
|
||||||
<!-- <el-form>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-form-item>
|
|
||||||
<el-input v-model="search_form.comment" placeholder="请输入" clearable />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="6">
|
|
||||||
<el-button type="primary" @click="doSearch">检索</el-button>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form> -->
|
|
||||||
<div class="create_dialog">
|
<div class="create_dialog">
|
||||||
<el-button type="primary" @click="on_create">新建</el-button>
|
<el-button type="primary" @click="handle_create">新建策略</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table ref="multipleTableRef" :data="strategy_list" style="width: 100%">
|
<el-table ref="multipleTableRef" :data="strategy_list" style="width: 100%">
|
||||||
@@ -66,30 +54,30 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<el-dialog v-model="createStrategyDialogVisible">
|
||||||
|
<create_strategy_dialog ref="dialogRef" @on-create="on_list"></create_strategy_dialog>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue'
|
||||||
|
import create_strategy_dialog from './dialog.vue'
|
||||||
import {
|
import {
|
||||||
get_strategies,
|
get_strategies,
|
||||||
create_strategy,
|
|
||||||
start_strategy,
|
start_strategy,
|
||||||
stop_strategy,
|
stop_strategy,
|
||||||
get_strategy_status,
|
get_strategy_status,
|
||||||
|
get_strategy_load_files,
|
||||||
|
get_vt_symbols
|
||||||
} from '../../api/cta_strategy'
|
} from '../../api/cta_strategy'
|
||||||
import { genFileId } from 'element-plus'
|
|
||||||
import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
|
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { strategyStore } from '../../store/strategy'
|
||||||
|
|
||||||
const upload = ref<UploadInstance>()
|
const store = strategyStore()
|
||||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
|
||||||
upload.value!.clearFiles()
|
let createStrategyDialogVisible = ref(false)
|
||||||
const file = files[0] as UploadRawFile
|
|
||||||
file.uid = genFileId()
|
|
||||||
upload.value!.handleStart(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Strategy = {
|
type Strategy = {
|
||||||
@@ -110,21 +98,22 @@ const on_list = () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const dialogRef = ref()
|
||||||
const on_create = () => {
|
const handle_create = () => {
|
||||||
|
createStrategyDialogVisible.value = true
|
||||||
|
dialogRef.value.clear_form()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const on_start = (row: any) => {
|
const on_start = (row: any) => {
|
||||||
start_strategy(row.strategy_name).then(res => {
|
start_strategy(row.strategy_name).then(res => {
|
||||||
|
row.status = 2
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const on_stop = (row: any) => {
|
const on_stop = (row: any) => {
|
||||||
stop_strategy(row.strategy_name).then(res => {
|
stop_strategy(row.strategy_name).then(res => {
|
||||||
|
row.status = 3
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,9 +129,31 @@ const on_status = (row: any) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// init process
|
const init = () => {
|
||||||
on_list()
|
on_list()
|
||||||
|
|
||||||
|
get_strategy_load_files().then(res => {
|
||||||
|
store.$patch({ class_names: res.data.class_names })
|
||||||
|
}).catch(error => {
|
||||||
|
ElMessage({
|
||||||
|
message: h('p', null, [
|
||||||
|
h('i', { style: 'color: teal' }, "读取策略文件失败"),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// get_vt_symbols().then(res => {
|
||||||
|
// console.log(res)
|
||||||
|
// }).catch(error => {
|
||||||
|
// ElMessage({
|
||||||
|
// message: h('p', null, [
|
||||||
|
// h('i', { style: 'color: teal' }, "读取vt_symbols失败"),
|
||||||
|
// ]),
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
// init process
|
||||||
|
init()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,15 @@
|
|||||||
<el-upload ref="upload" class="upload-demo" action="http://localhost:5000/trader/api/v1/strategy_file" :limit="1"
|
<el-upload ref="upload" class="upload-demo" action="http://localhost:5000/trader/api/v1/strategy_file" :limit="1"
|
||||||
:on-exceed="handleExceed" :auto-upload="false">
|
:on-exceed="handleExceed" :auto-upload="false">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<el-button type="primary">select file</el-button>
|
<el-button type="primary">添加策略文件</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
->
|
||||||
<el-button class="ml-3" type="success" @click="on_upload">
|
<el-button class="ml-3" type="success" @click="on_upload">
|
||||||
upload to server
|
上传策略文件
|
||||||
</el-button>
|
</el-button>
|
||||||
<template #tip>
|
<template #tip>
|
||||||
<div class="el-upload__tip text-red">
|
<div class="el-upload__tip text-red">
|
||||||
limit 1 file, new file will cover the old file
|
一次只能上传一个文件
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<div class="strategy_form">
|
||||||
|
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="140px" class="strategy-ruleForm"
|
||||||
|
:size="formSize" status-icon>
|
||||||
|
<el-form-item label="strategy_name" prop="strategy_name">
|
||||||
|
<el-input v-model="ruleForm.strategy_name" placeholder="demo_strategy_symbol" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="vt_symbol" prop="vt_symbol">
|
||||||
|
<el-select v-model="ruleForm.vt_symbol" placeholder="select a vt_symbol">
|
||||||
|
<el-option v-for="vt_symbol in store.vt_symbols" :value="vt_symbol" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="class_name" prop="class_name">
|
||||||
|
<el-select v-model="ruleForm.class_name" placeholder="select a class_name">
|
||||||
|
<el-option v-for="name in store.class_names" :value="name" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="setting:">
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" prop="setting">
|
||||||
|
<el-select v-model="ruleForm.setting.interval" placeholder="select a interval">
|
||||||
|
<el-option label="interval:1DAILY" value=24 />
|
||||||
|
<el-option label="interval:4HOUR" value=240 />
|
||||||
|
<el-option label="interval:1HOUR" value=60 />
|
||||||
|
<el-option label="interval:30MIN" value=30 />
|
||||||
|
<el-option label="interval:15MIN" value=15 />
|
||||||
|
<el-option label="interval:5MIN" value=5 />
|
||||||
|
<el-option label="interval:1MIN" value=1 />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- <el-form-item label="" prop="name">
|
||||||
|
<el-input v-model="ruleForm.name" placeholder="Please input">
|
||||||
|
<template #prepend>interval:</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item> -->
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="submitForm(ruleFormRef)">Create</el-button>
|
||||||
|
<el-button @click="resetForm(ruleFormRef)">Reset</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { create_strategy } from '../../api/cta_strategy'
|
||||||
|
import { h } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { strategyStore } from '../../store/strategy'
|
||||||
|
|
||||||
|
const store = strategyStore()
|
||||||
|
|
||||||
|
const formSize = ref('default')
|
||||||
|
const ruleFormRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
const ruleForm = reactive({
|
||||||
|
strategy_name: '',
|
||||||
|
class_name: '',
|
||||||
|
vt_symbol: '',
|
||||||
|
setting: {
|
||||||
|
interval: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
const clear_form = () => {
|
||||||
|
ruleForm.strategy_name = ''
|
||||||
|
ruleForm.class_name = ''
|
||||||
|
ruleForm.vt_symbol = ''
|
||||||
|
ruleForm.setting.interval = ''
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
clear_form
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
strategy_name: [
|
||||||
|
{ required: true, message: 'Please input strategy name', trigger: 'blur' },
|
||||||
|
{ min: 8, max: 30, message: 'Length should be 8 to 30', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
interval: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please select interval',
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class_name: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please select class_name'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
vt_symbol: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please select vt_symbol'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['on-create'])
|
||||||
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
create_strategy(ruleForm).then(res => {
|
||||||
|
emit('on-create')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage({
|
||||||
|
message: h('p', null, [
|
||||||
|
h('i', { style: 'color: teal' }, 'error submit!' + fields),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
formEl.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.el-button--text {
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer button:first-child {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user