市场行情 页面修改

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