市场行情 页面修改
This commit is contained in:
+1
-1
@@ -72,7 +72,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
path: '/strategy',
|
||||
component: () => import('../view/trader/cta_strategy_file.vue'),
|
||||
meta: {
|
||||
name: '策略文件'
|
||||
name: '策略模板'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const toPercent = (num: number) => {
|
||||
return (num * 100).toFixed(2) + "%"
|
||||
}
|
||||
|
||||
export { toPercent }
|
||||
@@ -531,7 +531,7 @@ const onUploadImg = async (files: FileList, callback: (urls: string[]) => void)
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData = new FormData()
|
||||
formData.append('img', file)
|
||||
onUploadImg(formData,)
|
||||
// onUploadImg(formData,)
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
+33
-31
@@ -52,20 +52,22 @@ import Cookies from 'js-cookie';
|
||||
import { reactive } from 'vue';
|
||||
import { getBlogs, getBtName, publish, publishAll } from '../../api/blogView'
|
||||
import router from '../../router/index'
|
||||
type Blog = {
|
||||
bid: string,
|
||||
btId: string,
|
||||
btName: string,
|
||||
title: string,
|
||||
blog_prex: string,
|
||||
|
||||
// -- INTERFACE OR TYPE DEFINITION --
|
||||
interface Blog {
|
||||
bid: string
|
||||
btId: string
|
||||
btName: string
|
||||
title: string
|
||||
blog_prex: string
|
||||
content: string
|
||||
}
|
||||
type Blog_Type = {
|
||||
btId: string,
|
||||
interface Blog_Type {
|
||||
btId: string
|
||||
btName: string
|
||||
}
|
||||
|
||||
// 変数定義
|
||||
// -- REACTIVE OBJECT --
|
||||
const form = reactive({
|
||||
key_word: '',
|
||||
btId: '',
|
||||
@@ -78,26 +80,7 @@ const form = reactive({
|
||||
const data_list = reactive<Blog[]>([])
|
||||
const btNameList = reactive<Blog_Type[]>([])
|
||||
|
||||
// 関数定義
|
||||
const init = () => {
|
||||
getBlogs({}).then(response => {
|
||||
response.data.forEach((item: Blog) => {
|
||||
data_list.push(item)
|
||||
})
|
||||
})
|
||||
getBtName().then(response => {
|
||||
btNameList.push({ btId: "", btName: "选择分类" })
|
||||
response.data.forEach((item: any) => {
|
||||
const bts = {
|
||||
btId: item.btId,
|
||||
btName: item.btName
|
||||
}
|
||||
btNameList.push(bts)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// -- EVENT DEFINITION
|
||||
const onSubmit = () => {
|
||||
getBlogs(form).then(response => {
|
||||
data_list.splice(0, data_list.length);
|
||||
@@ -134,9 +117,28 @@ const publishbyBid = (bid: string) => {
|
||||
publish(bid)
|
||||
}
|
||||
|
||||
// 初期化処理
|
||||
init()
|
||||
/**
|
||||
* AUTO INVOKE FUNCTION
|
||||
*/
|
||||
(() => {
|
||||
|
||||
getBlogs({}).then(response => {
|
||||
response.data.forEach((item: Blog) => {
|
||||
data_list.push(item)
|
||||
})
|
||||
})
|
||||
getBtName().then(response => {
|
||||
btNameList.push({ btId: "", btName: "选择分类" })
|
||||
response.data.forEach((item: any) => {
|
||||
const bts = {
|
||||
btId: item.btId,
|
||||
btName: item.btName
|
||||
}
|
||||
btNameList.push(bts)
|
||||
})
|
||||
})
|
||||
|
||||
})()
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
+46
-23
@@ -45,28 +45,30 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="手动下单" name="2" style="display: flex;">
|
||||
<el-collapse-item title="手动下单" name="2">
|
||||
|
||||
<el-select v-model="vt_symbol" placeholder="select a vt_symbol" @change="select_contract">
|
||||
<el-option v-for="symbol in store.subscribe_vt_symbols" :value="symbol" />
|
||||
</el-select>
|
||||
<div style="height: 10px;"></div>
|
||||
<el-row>
|
||||
<el-col :span="2">
|
||||
<el-col :span="5">
|
||||
<el-radio-group v-model="direction">
|
||||
<el-radio-button label="多" />
|
||||
<el-radio-button label="空" />
|
||||
</el-radio-group>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-col :span="4">
|
||||
<el-radio-group v-model="offset">
|
||||
<el-radio-button label="开" />
|
||||
<el-radio-button label="平" />
|
||||
</el-radio-group>
|
||||
</el-col>
|
||||
<el-col :span="1"></el-col>
|
||||
<el-col :span="3">
|
||||
<el-select v-model="vt_symbol" placeholder="select a vt_symbol" @change="select_contract">
|
||||
<el-option v-for="symbol in store.subscribe_vt_symbols" :value="symbol" />
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="1"></el-col>
|
||||
<el-col :span="4">
|
||||
</el-row>
|
||||
<div style="height: 10px;"></div>
|
||||
<el-row>
|
||||
|
||||
<el-col :span="5">
|
||||
<el-input-number v-model="volume" :min="1" :max="10" @change="handleChange" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
@@ -75,7 +77,9 @@
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" @click="on_order">下单</el-button>
|
||||
</el-col>
|
||||
<el-col :span="7"></el-col>
|
||||
</el-row>
|
||||
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="持仓一览" name="3">
|
||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
@@ -134,14 +138,19 @@
|
||||
import { ElMessage, TabsPaneContext } from 'element-plus'
|
||||
import { reactive, ref, h, onMounted, onUnmounted } from 'vue'
|
||||
import { get_accounts, send_order, get_tick } from '../../api/capital'
|
||||
import { strategyStore } from '../../store/strategy';
|
||||
type AccountData = {
|
||||
import { strategyStore } from '../../store/strategy'
|
||||
|
||||
// -- IMPORT --
|
||||
const store = strategyStore()
|
||||
|
||||
// -- INTERFACE OR TYPE DEFINITION --
|
||||
interface AccountData {
|
||||
gateway_name: string
|
||||
account_id: string
|
||||
balance: number
|
||||
frozen: number
|
||||
}
|
||||
type PositionData = {
|
||||
interface PositionData {
|
||||
symbol: string
|
||||
exchange: string
|
||||
direction: string
|
||||
@@ -151,7 +160,7 @@ type PositionData = {
|
||||
pnl: number
|
||||
yd_volume: number
|
||||
}
|
||||
type OrderData = {
|
||||
interface OrderData {
|
||||
symbol: string
|
||||
exchange: string
|
||||
direction: string
|
||||
@@ -165,7 +174,7 @@ type OrderData = {
|
||||
// datetime :datetime
|
||||
reference: string
|
||||
}
|
||||
type TradeData = {
|
||||
interface TradeData {
|
||||
symbol: string
|
||||
exchange: string
|
||||
direction: string
|
||||
@@ -176,7 +185,14 @@ type TradeData = {
|
||||
offset: string
|
||||
// datetime: datetime
|
||||
}
|
||||
const store = strategyStore()
|
||||
|
||||
// -- REACTIVE OBJECT --
|
||||
const account_datas = reactive<AccountData[]>([])
|
||||
const positions_data = reactive<PositionData[]>([])
|
||||
const trades_data = reactive<TradeData[]>([])
|
||||
const orders_data = reactive<OrderData[]>([])
|
||||
|
||||
// -- REF OBJECT --
|
||||
const vt_symbol = ref<string>("")
|
||||
const direction = ref('多')
|
||||
const offset = ref('开')
|
||||
@@ -184,12 +200,9 @@ const activeName = ref(1)
|
||||
const volume = ref(1)
|
||||
const price = ref(3000)
|
||||
const timer = ref(0)
|
||||
const account_datas = reactive<AccountData[]>([])
|
||||
const positions_data = reactive<PositionData[]>([])
|
||||
const trades_data = reactive<TradeData[]>([])
|
||||
const orders_data = reactive<OrderData[]>([])
|
||||
const activeNames = ref(['1'])
|
||||
|
||||
// -- EVENT DEFINITION
|
||||
const on_query_accounts = () => {
|
||||
get_accounts().then(res => {
|
||||
account_datas.length = 0
|
||||
@@ -212,14 +225,15 @@ const on_query_accounts = () => {
|
||||
})
|
||||
|
||||
})
|
||||
return on_query_accounts
|
||||
}
|
||||
|
||||
const select_contract = () => {
|
||||
get_tick(vt_symbol.value).then(res => {
|
||||
price.value = res.data.tick.last_price
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||
console.log(tab, event)
|
||||
}
|
||||
@@ -227,6 +241,7 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||
const handleChange = (value: number) => {
|
||||
console.log(value)
|
||||
}
|
||||
|
||||
const on_order = () => {
|
||||
|
||||
""
|
||||
@@ -251,13 +266,21 @@ const on_order = () => {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AUTO INVOKE FUNCTION
|
||||
*/
|
||||
(() => {
|
||||
|
||||
store.select_subscribe_vt_symbols()
|
||||
onMounted(() => {
|
||||
clearInterval(timer.value)
|
||||
timer.value = window.setInterval(on_query_accounts, 3000);
|
||||
timer.value = window.setInterval(on_query_accounts(), 3000);
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.clearInterval(timer.value);
|
||||
})
|
||||
})()
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -30,13 +30,15 @@
|
||||
<el-table @row-contextmenu="rightClickRow" @cell-mouse-enter="rowMouseEnter" @cell-mouse-leave="rowMouseLeave"
|
||||
:data="ticks_data" style="width: 100%">
|
||||
<el-table-column fixed prop="symbol" label="symbol" width="80" />
|
||||
<el-table-column fixed prop="exchange" label="exchange" width="100" />
|
||||
<el-table-column fixed prop="name" label="Name" width="120" />
|
||||
<el-table-column fixed prop="last_price" label="last_price" width="120" />
|
||||
<el-table-column fixed prop="volume" label="volume" width="100" />
|
||||
<el-table-column fixed prop="open_price" label="open_price" width="120" />
|
||||
<el-table-column fixed prop="high_price" label="high_price" width="120" />
|
||||
<el-table-column fixed prop="low_price" label="low_price" width="120" />
|
||||
<el-table-column prop="exchange" label="exchange" width="100" />
|
||||
<el-table-column prop="name" label="Name" width="120" />
|
||||
<el-table-column prop="last_price" label="last_price" width="120" />
|
||||
<el-table-column prop="volume" label="volume" width="100" />
|
||||
<el-table-column prop="open_price" label="open_price" width="120" />
|
||||
<el-table-column prop="high_price" label="high_price" width="120" />
|
||||
<el-table-column prop="low_price" label="low_price" width="100" />
|
||||
<el-table-column prop="differ" label="differ" width="70" />
|
||||
<el-table-column prop="differ_percent" label="differ_per" :formatter="Formatter" width="120" />
|
||||
</el-table>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
@@ -56,7 +58,8 @@ import { ref, h, onMounted, onUnmounted, reactive, getCurrentInstance } from 'vu
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { get_ticks, subscribe, concel_subscribe } from '../../api/capital'
|
||||
import { strategyStore } from '../../store/strategy'
|
||||
import { Contextmenu, ContextmenuItem } from "v-contextmenu";
|
||||
import { Contextmenu, ContextmenuItem } from "v-contextmenu"
|
||||
import { toPercent } from '../../utils/number'
|
||||
|
||||
import * as echarts from 'echarts'
|
||||
// -- IMPORT --
|
||||
@@ -73,6 +76,8 @@ interface TickData {
|
||||
open_price: number
|
||||
high_price: number
|
||||
low_price: number
|
||||
differ: number
|
||||
differ_percent: number
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +104,8 @@ const on_subscribe = () => {
|
||||
h('i', { style: 'color: green' }, "行情订阅成功"),
|
||||
]),
|
||||
})
|
||||
store.select_subscribe_vt_symbols()
|
||||
on_ticks()
|
||||
}).catch(error => {
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
@@ -108,6 +115,31 @@ const on_subscribe = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const concelSubscribe = () => {
|
||||
if (!selection.value) {
|
||||
return
|
||||
}
|
||||
concel_subscribe(selection.value).then(res => {
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
h('i', { style: 'color: green' }, "取消订阅成功"),
|
||||
]),
|
||||
})
|
||||
on_ticks()
|
||||
}).catch(error => {
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
h('i', { style: 'color: red' }, "取消订阅失败"),
|
||||
]),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const Formatter = (row, column) => {
|
||||
let diff = (row.last_price - row.open_price) / row.open_price
|
||||
return toPercent(diff)
|
||||
}
|
||||
|
||||
const rowMouseEnter = (row: any, column: any, cell: any, event: any) => {
|
||||
selection.value = row.symbol + "." + row.exchange
|
||||
console.log(selection.value)
|
||||
@@ -141,25 +173,7 @@ const on_ticks = () => {
|
||||
ticks_data.push(element)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const concelSubscribe = () => {
|
||||
if (!selection.value) {
|
||||
return
|
||||
}
|
||||
concel_subscribe(selection.value).then(res => {
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
h('i', { style: 'color: green' }, "取消订阅成功"),
|
||||
]),
|
||||
})
|
||||
}).catch(error => {
|
||||
ElMessage({
|
||||
message: h('p', null, [
|
||||
h('i', { style: 'color: red' }, "取消订阅失败"),
|
||||
]),
|
||||
})
|
||||
})
|
||||
return on_ticks
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +183,7 @@ const concelSubscribe = () => {
|
||||
|
||||
onMounted(() => {
|
||||
clearInterval(timer.value)
|
||||
timer.value = window.setInterval(on_ticks, 3000);
|
||||
timer.value = window.setInterval(on_ticks(), 3000);
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.clearInterval(timer.value)
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<el-upload ref="upload" class="upload-demo" action="http://localhost:5000/trader/api/v1/strategy_file" :limit="1"
|
||||
:on-exceed="handleExceed" :auto-upload="false">
|
||||
<template #trigger>
|
||||
<el-button type="primary">添加策略文件</el-button>
|
||||
<el-button type="primary">添加策略模板</el-button>
|
||||
</template>
|
||||
->
|
||||
<el-button class="ml-3" type="success" @click="on_upload">
|
||||
上传策略文件
|
||||
上传策略模板
|
||||
</el-button>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip text-red">
|
||||
@@ -78,23 +78,20 @@ import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
|
||||
import { h } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const upload = ref<UploadInstance>()
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
upload.value!.clearFiles()
|
||||
const file = files[0] as UploadRawFile
|
||||
file.uid = genFileId()
|
||||
upload.value!.handleStart(file)
|
||||
}
|
||||
|
||||
|
||||
type StrategyFile = {
|
||||
file_name: string,
|
||||
class_name: string,
|
||||
// -- INTERFACE OR TYPE DEFINITION --
|
||||
interface StrategyFile {
|
||||
file_name: string
|
||||
class_name: string
|
||||
status: string
|
||||
}
|
||||
|
||||
// -- REACTIVE OBJECT --
|
||||
const strategy_file_list = reactive<StrategyFile[]>([])
|
||||
|
||||
// -- REF OBJECT --
|
||||
const upload = ref<UploadInstance>()
|
||||
|
||||
// -- EVENT DEFINITION
|
||||
const on_list = () => {
|
||||
get_strategy_files().then(res => {
|
||||
strategy_file_list.length = 0
|
||||
@@ -104,6 +101,13 @@ const on_list = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
upload.value!.clearFiles()
|
||||
const file = files[0] as UploadRawFile
|
||||
file.uid = genFileId()
|
||||
upload.value!.handleStart(file)
|
||||
}
|
||||
|
||||
const on_upload = () => {
|
||||
|
||||
upload.value!.submit()
|
||||
@@ -145,10 +149,15 @@ const on_remove = (row: any) => {
|
||||
})
|
||||
}
|
||||
|
||||
// init process
|
||||
|
||||
/**
|
||||
* AUTO INVOKE FUNCTION
|
||||
*/
|
||||
(() => {
|
||||
|
||||
on_list()
|
||||
|
||||
|
||||
})()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user