[Add]增加WebTrader的网页前端界面

This commit is contained in:
vn.py 2018-02-09 17:09:18 +08:00
parent 4691e0c152
commit fb6834aaff
4 changed files with 1123 additions and 90 deletions

View File

@ -2,7 +2,7 @@
{
"name": "double ema",
"className": "DoubleMaStrategy",
"vtSymbol": "rb1805"
"vtSymbol": "IF1802"
},
{

View File

@ -41,20 +41,19 @@ with open("WEB_setting.json") as f:
setting = json.load(f)
USERNAME = setting['username']
PASSWORD = setting['password']
TOKEN = base64.encodestring(TODAY+PASSWORD).replace('\n', '')
TOKEN = base64.encodestring(TODAY+PASSWORD).replace('\n','')
# 创建Flask对象
from flask import Flask
from flask.ext.restful import Api, Resource, reqparse
from flask.ext.socketio import SocketIO
from flask.ext.cors import CORS
from flask_cors import *
app = Flask(__name__)
CORS(app, supports_credentials=True)
api = Api(app)
socketio = SocketIO(app)
cors = CORS(app, supports_credentials=True)
# 创建资源
@ -78,9 +77,9 @@ class Token(Resource):
password = args['password']
if username == USERNAME and password == PASSWORD:
return TOKEN
return {'result_code':'success','data':TOKEN}
else:
return ''
return {'result_code':'error','message':'wrong username or password'}
########################################################################
@ -101,11 +100,14 @@ class Gateway(Resource):
"""查询"""
args = self.parser.parse_args()
token = args['token']
print token
print TOKEN
if token != TOKEN:
return None
print 'token error'
return {'result_code':'error','message':'token error'}
l = me.getAllGatewayDetails()
return l
return {'result_code':'success','data':l}
#----------------------------------------------------------------------
def post(self):
@ -113,10 +115,12 @@ class Gateway(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
print 'token error'
return {'result_code':'error','message':'token error'}
gatewayName = args['gatewayName']
me.connect(gatewayName)
return {'result_code':'success','data':''}
########################################################################
@ -141,7 +145,6 @@ class Order(Resource):
self.deleteParser = reqparse.RequestParser()
self.deleteParser.add_argument('vtOrderID')
self.deleteParser.add_argument('token')
self.deleteParser.add_argument('cancelAll')
super(Order, self).__init__()
@ -151,11 +154,11 @@ class Order(Resource):
args = self.getParser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getAllOrders()
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
#----------------------------------------------------------------------
def post(self):
@ -163,8 +166,8 @@ class Order(Resource):
args = self.postParser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
print args
vtSymbol = args['vtSymbol']
price = args['price']
volume = args['volume']
@ -174,18 +177,22 @@ class Order(Resource):
contract = me.getContract(vtSymbol)
if not contract:
return ''
return {'result_code':'error','message':'contract error'}
priceType_map = {'PRICETYPE_LIMITPRICE' : u'限价','PRICETYPE_MARKETPRICE' : u'市价','PRICETYPE_FAK' : u'FAK','PRICETYPE_FOK' : u'FOK'}
direction_map = {'DIRECTION_LONG' : u'','DIRECTION_SHORT' : u''}
offset_map = {'OFFSET_OPEN' : u'开仓', 'OFFSET_CLOSE' : u'平仓','OFFSET_CLOSETODAY' : u'平今','OFFSET_CLOSEYESTERDAY' : u'平昨'}
req = VtOrderReq()
req.symbol = contract.symbol
req.exchange = contract.exchange
req.price = float(price)
req.volume = int(volume)
req.priceType = priceType
req.direction = direction
req.offset = offset
vtOrderID = me.sendOrder(req, contract.gatewayName)
return vtOrderID
req.symbol = contract.symbol
req.exchange = contract.exchange
req.price = float(price)
req.volume = int(volume)
req.priceType = priceType_map[ priceType ]
req.direction = direction_map[ direction ]
req.offset = offset_map[ offset ]
vtOrderID = me.sendOrder(req, contract.gatewayName)
return {'result_code':'success','data':vtOrderID}
#----------------------------------------------------------------------
def delete(self):
@ -193,34 +200,20 @@ class Order(Resource):
args = self.deleteParser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
cancelAll = args['cancelAll']
vtOrderID = args['vtOrderID']
# 单一撤单
if not cancelAll:
vtOrderID = args['vtOrderID']
order = me.getOrder(vtOrderID)
if not order:
return False
req = VtCancelOrderReq()
req.orderID = order.orderID
req.exchange = order.exchange
req.symbol = order.symbol
me.cancelOrder(req, order.gatewayName)
# 全撤
else:
l = me.getAllWorkingOrders()
for order in l:
req = VtCancelOrderReq()
req.orderID = order.orderID
req.exchange = order.exchange
req.symbol = order.symbol
me.cancelOrder(req, order.gatewayName)
order = me.getOrder(vtOrderID)
if not order:
return {'result_code':'error','message':'vtOrderID error'}
req = VtCancelOrderReq()
req.orderID = order.orderID
req.exchange = order.exchange
req.symbol = order.symbol
me.cancelOrder(req, order.gatewayName)
return {'result_code':'success','data':""}
########################################################################
class Trade(Resource):
@ -240,11 +233,11 @@ class Trade(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getAllTrades()
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
########################################################################
@ -265,11 +258,11 @@ class Account(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getAllAccounts()
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
########################################################################
@ -290,11 +283,12 @@ class Position(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getAllPositions()
print 'position',data
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
########################################################################
@ -316,11 +310,12 @@ class Contract(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getAllContracts()
print 'Contract',data
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
########################################################################
@ -341,11 +336,11 @@ class Log(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getLog()
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
########################################################################
@ -366,11 +361,11 @@ class Error(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
data = me.getError()
l = [o.__dict__ for o in data]
return l
return {'result_code':'success','data':l}
########################################################################
@ -388,23 +383,25 @@ class Tick(Resource):
#----------------------------------------------------------------------
def post(self):
"""订阅"""
print 'posting to tick'
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
vtSymbol = args['vtSymbol']
contract = me.getContract(vtSymbol)
if not contract:
return False
return {'result_code':'error','message':'contract error'}
req = VtSubscribeReq()
req.symbol = contract.symbol
req.exchange = contract.exchange
req.vtSymbol = contract.vtSymbol
me.subscribe(req, contract.gatewayName)
return True
return {'result_code':'success','data':''}
########################################################################
@ -425,7 +422,7 @@ class CtaStrategyInit(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
name = args['name']
@ -434,6 +431,7 @@ class CtaStrategyInit(Resource):
engine.initAll()
else:
engine.initStrategy(name)
return {'result_code':'success','data':''}
########################################################################
@ -454,7 +452,7 @@ class CtaStrategyStart(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
name = args['name']
@ -463,6 +461,7 @@ class CtaStrategyStart(Resource):
engine.startAll()
else:
engine.startStrategy(name)
return {'result_code':'success','data':''}
########################################################################
@ -483,7 +482,7 @@ class CtaStrategyStop(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
name = args['name']
@ -492,31 +491,30 @@ class CtaStrategyStop(Resource):
engine.stopAll()
else:
engine.stopStrategy(name)
return {'result_code':'success','data':''}
########################################################################
class CtaStrategyName(Resource):
"""获取策略名"""
"""»ñÈ¡²ßÂÔÃû"""
#----------------------------------------------------------------------
def __init__(self):
"""初始化"""
"""³õʼ»¯"""
self.parser = reqparse.RequestParser()
self.parser.add_argument('token')
super(CtaStrategyName, self).__init__()
#----------------------------------------------------------------------
def get(self):
"""获取策略名"""
"""»ñÈ¡²ßÂÔÃû"""
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
engine = me.getApp('CtaStrategy')
l = engine.getStrategyNames()
return l
return {'result_code':'success','data':l}
########################################################################
class CtaStrategyLoad(Resource):
@ -535,12 +533,12 @@ class CtaStrategyLoad(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
engine = me.getApp('CtaStrategy')
engine.loadSetting()
l = engine.getStrategyNames()
return l
return {'result_code':'success','data':l}
########################################################################
@ -561,12 +559,13 @@ class CtaStrategyParam(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
name = args['name']
engine = me.getApp('CtaStrategy')
return engine.getStrategyParam(name)
l = engine.getStrategyParam(name)
return {'result_code':'success','data':l}
########################################################################
@ -587,12 +586,13 @@ class CtaStrategyVar(Resource):
args = self.parser.parse_args()
token = args['token']
if token != TOKEN:
return None
return {'result_code':'error','message':'token error'}
name = args['name']
engine = me.getApp('CtaStrategy')
return engine.getStrategyVar(name)
l = engine.getStrategyVar(name)
return {'result_code':'success','data':l}
# 注册资源
@ -621,13 +621,16 @@ api.add_resource(CtaStrategyName, '/ctastrategy/name')
def handleEvent(event):
"""处理事件"""
eventType = event.type_
eventData = event.dict_['data']
if not isinstance(eventData, dict):
eventData = eventData.__dict__
eventData = eventData.__dict__
if( eventType == 'eTick.' ):
del eventData['datetime']
socketio.emit(eventType, eventData)
#print eventData
ee.register(EVENT_TICK, handleEvent)
@ -640,8 +643,7 @@ ee.register(EVENT_LOG, handleEvent)
ee.register(EVENT_ERROR, handleEvent)
ee.register(EVENT_CTA_LOG, handleEvent)
ee.register(EVENT_CTA_STRATEGY, handleEvent)
if __name__ == '__main__':
socketio.run(app)
socketio.run(app,debug=True,host='0.0.0.0',port=5000)

View File

@ -0,0 +1,172 @@
html {
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
.body-left .el-row,
.body-left button,
.el-col {
margin-bottom: 8px;
}
.el-main {
padding: 0px;
}
.el-button+.el-button {
margin-left: 0px;
}
.body-left__btn {
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
margin-top: 32px;
}
.el-table th {
background-color: #F5F5F5;
padding: 6px 0px;
}
html,
.body {
height: 100%;
overflow: hidden;
}
.body-left__connection {
font-size: 12px;
position: fixed;
bottom: 0px;
left: 0px;
width: 330px;
background-color: #f5f5f5;
padding: 10px 8px;
border-top: 1px solid #bdbdbd;
color: #909399;
}
.body-left__connection p {
display: inline;
color: #F56C6C;
}
.el-tabs {
margin-top: -1px;
z-index: 2;
}
.el-tabs--card>.el-tabs__header .el-tabs__nav {
border-radius: 0px;
}
.el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
border-bottom: 2px solid #409eff;
transition: all 0.5s ease-in-out;
/*background-color: rgba(64, 158, 255, 1);
color: white;*/
}
.el-input {
width: 130px;
}
.el-tabs__header {
margin-bottom: 0px !important;
}
.el-table__fixed,
.el-table__fixed-right {
-webkit-box-shadow: none;
box-shadow: none;
}
.el-table .caret-wrapper {
width: 4px;
}
.el-table {
font-size: 12px;
}
.el-table .cell,
.el-table th div,
.el-table--border td:first-child .cell,
.el-table--border th:first-child .cell {
padding-left: 0px;
text-align: center;
}
.el-table th>.cell {
text-align: center;
}
.el-form-item__label {
line-height: 20px;
}
.el-form-item__label,
.el-form p {
display: inline;
font-size: 14px;
color: #606266;
}
.el-input--suffix .el-input__inner {
padding-right: 0px;
}
.el-input-number .el-input__inner {
padding-left: 0px;
padding-right: 0px;
}
.el-input-number {
width: 130px;
}
.el-table__row:hover {
cursor: pointer;
}
.el-input-group__append,
.el-input-group__prepend {
padding: 0 8px;
font-size: 10px;
}
.leftTrade {
width: 320px;
overflow-y: scroll;
}
.cta-frame{
height: 60%;
border:1px solid #ebeef5;
padding:16px;
}
.cta-frame__top{
overflow-y: scroll;
}
.cta-frame__top_section{
padding:8px 12px;
/* background-color: #FAFAFA; */
margin-bottom:12px;
border:1px dashed #ebeef5;
}
.cta-frame__top .itemName{
color:#409EFF;
margin:12px 0px 24px 0px;
}
.itemName +button{
margin-bottom: 24px;
}
.cta-frame__bottom{
height: 120px;
}

View File

@ -0,0 +1,859 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcss.com/socket.io/2.0.4/socket.io.slim.js"></script>
<link href="https://cdn.bootcss.com/element-ui/2.0.11/theme-chalk/index.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div id="app">
<template>
<el-tabs v-model="activeTab" @tab-click="handleTab">
<el-tab-pane label="交易" name="home">
<el-container style="margin-top: 12px;">
<el-aside class="leftTrade" :style="{ height: leftTradeHeight, width:'320px'}">
<el-row>
<el-form class="el-col el-col el-col-24" ref="form" :model="form" :rules="formRules" label-width="50px" show-message="true" inline-message="true" validate="formValidate">
<div class="el-form-item">
<label class="el-form-item__label" style="width: 50px;">代码</label>
<div class="el-form-item__content" style="margin-left: 50px;">
<div class="el-input--suffix el-input el-input-group el-input-group--append">
<input autocomplete="off" type="text" rows="2" validateevent="true" clearable="true" class="el-input__inner" @keyup.enter="onSubscribe" v-model="form.vtSymbol">
<div class="el-input-group__append">
<button type="button" class="el-button el-button--default" @click="onSubscribe">
<!-- <i class="el-icon-plus"></i> -->订阅</button>
</div>
</div>
<p>卖五</p>
</div>
</div>
<!-- <el-form-item label="代码">
<el-input class="el-input--suffix" clearable @keyup.enter="enter" v-model="form.vtSymbol">
<el-button slot="append" @click="onSubscribe" v-loading="loading.subScribe" icon="el-icon-plus"></el-button>
</el-input>
<p>卖五</p>
</el-form-item> -->
<el-form-item label="名称">
<el-input class="el-input--suffix" v-model="form.name"></el-input>
<p>卖四</p>
</el-form-item>
<el-form-item label="方向类型">
<el-select v-model="form.direction" placeholder="请选择">
<el-option label="多" value="DIRECTION_LONG"></el-option>
<el-option label="空" value="DIRECTION_SHORT"></el-option>
</el-select>
<p>卖三</p>
</el-form-item>
<el-form-item label="开平">
<el-select v-model="form.offset" placeholder="请选择">
<el-option label="开仓" value="OFFSET_OPEN"></el-option>
<el-option label="平仓" value="OFFSET_CLOSETODAY"></el-option>
<el-option label="平昨" value="OFFSET_CLOSEYESTERDAY"></el-option>
<el-option label="平今" value="OFFSET_CLOSETODAY"></el-option>
</el-select>
<p>卖二</p>
</el-form-item>
<el-form-item label="价格">
<el-input class="el-input--suffix" v-model="form.lastPrice"></el-input>
<p>卖一 {{leftTrade.askPrice1}} {{leftTrade.askVolume1}}</p>
</el-form-item>
<el-form-item label="数量">
<el-input-number :min="1" class="el-input--suffix" v-model="form.volume"></el-input-number>
<p>最新 {{leftTrade.lastPrice}} {{leftTrade.priceRatio}}</p>
</el-form-item>
<el-form-item label="价格类型">
<el-select v-model="form.priceType" placeholder="请选择">
<el-option label="限价" value="PRICETYPE_LIMITPRICE"></el-option>
<el-option label="市价" value="PRICETYPE_MARKETPRICE"></el-option>
<el-option label="FAK" value="PRICETYPE_FAK"></el-option>
<el-option label="FOK" value="PRICETYPE_FOK"></el-option>
</el-select>
<p>买一 {{leftTrade.bidPrice1}} {{leftTrade.bidVolume1}}</p>
</el-form-item>
<el-form-item label="交易接口">
<el-select v-model="form.region" placeholder="请选择">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
<p>买二</p>
</el-form-item>
</el-form>
</el-row>
<el-row class="body-left__btn">
<div class="el-col el-col-18">
<el-button class="el-col el-col-24" type="primary" @click="onSubmit" v-loading="loading.order">发单</el-button>
<el-button class="el-col el-col-24">全撤</el-button>
</div>
</el-row>
<el-row class="body-left__connection">
<div>服务器连接:
<p>{{connection}}</p>
</div>
</el-row>
</el-aside>
<el-main>
<el-row :gutter="10">
<el-col :span="24">
<template>
<el-table :data="eTick" :height="table_height" @cell-click="clickTick" border style="width: 100%">
<el-table-column sortable fixed prop="symbol" width="80" label="合约代码">
</el-table-column>
<el-table-column sortable prop="available" label="名称">
</el-table-column>
<el-table-column sortable prop="lastPrice" label="最新价">
</el-table-column>
<el-table-column sortable prop="preClosePrice" label="昨收盘">
</el-table-column>
<el-table-column sortable prop="volume" label="成交量">
</el-table-column>
<el-table-column sortable prop="openInterest" label="持仓量">
</el-table-column>
<el-table-column sortable prop="openPrice" label="开盘价">
</el-table-column>
<el-table-column sortable prop="highPrice" label="最高价">
</el-table-column>
<el-table-column sortable prop="lowPrice" label="最低价">
</el-table-column>
<el-table-column sortable prop="bidPrice1" label="买一价">
</el-table-column>
<el-table-column sortable prop="bidVolume1" label="买一量">
</el-table-column>
<el-table-column sortable prop="askPrice1" label="卖一价">
</el-table-column>
<el-table-column sortable prop="askVolume1" label="卖一量">
</el-table-column>
<el-table-column sortable prop="date" label="日期">
</el-table-column>
<el-table-column sortable prop="gatewayName" label="接口">
</el-table-column>
</el-table>
</template>
</el-col>
<el-col :span="24">
<template>
<el-table :data="order" :height="table_height" border @cell-dblclick="dOrder">
<el-table-column fixed sortable prop="orderID" width="80" label="委托编号">
</el-table-column>
<el-table-column sortable width="80" prop="symbol" label="合约代码">
</el-table-column>
<el-table-column sortable width="80" prop="name" label="名称">
</el-table-column>
<el-table-column sortable width="80" prop="direction" label="方向">
</el-table-column>
<el-table-column sortable width="80" prop="offset" label="开平">
</el-table-column>
<el-table-column sortable width="80" prop="price" label="价格">
</el-table-column>
<el-table-column sortable width="80" prop="totalVolume" label="委托数量">
</el-table-column>
<el-table-column sortable width="80" prop="tradedVolume" label="成交数量">
</el-table-column>
<el-table-column sortable width="80" prop="status" label="委托状态">
</el-table-column>
<el-table-column sortable prop="address" label="委托时间">
</el-table-column>
<el-table-column sortable prop="cancelTime" label="撤销时间">
</el-table-column>
<el-table-column sortable width="80" prop="gatewayName" label="接口">
</el-table-column>
</el-table>
</template>
</el-col>
<el-col :span="24">
<el-row :gutter="10">
<el-col :span="12">
<template>
<el-tabs v-model="activeTabLeft" type="card" @tab-click="handleTabLeft">
<el-tab-pane label="成交" name="trade">
<el-table :data="trade" :height="table_height" border style="width: 100%">
<el-table-column fixed sortable width="80" prop="tradeID" label="成交编号">
</el-table-column>
<el-table-column sortable width="80" prop="orderID" label="委托编号">
</el-table-column>
<el-table-column sortable width="80" prop="symbol" label="合约代码">
</el-table-column>
<el-table-column sortable width="80" prop="askPrice3" label="名称">
</el-table-column>
<el-table-column sortable width="80" prop="direction" label="方向">
</el-table-column>
<el-table-column sortable width="80" prop="offset" label="开平">
</el-table-column>
<el-table-column sortable width="80" prop="price" label="价格">
</el-table-column>
<el-table-column sortable width="80" prop="volume" label="成交量">
</el-table-column>
<el-table-column sortable width="80" prop="tradeTime" label="成交时间">
</el-table-column>
<el-table-column sortable width="80" prop="gatewayName" label="接口">
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="错误" name="error">
<el-table :data="error" :height="table_height" border style="width: 100%">
<el-table-column sortable prop="errorTime" width="80" label="错误时间">
</el-table-column>
<el-table-column sortable width="80" prop="errorID" label="错误代码">
</el-table-column>
<el-table-column sortable width="80" prop="gatewayName" label="接口">
</el-table-column>
<el-table-column sortable prop="errorMsg" label="错误信息">
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="日志" name="log">
<el-table :data="log" :height="table_height" border style="width: 100%">
<el-table-column fixed width="80" sortable prop="logTime" label="时间">
</el-table-column>
<el-table-column sortable prop="logContent" label="内容">
</el-table-column>
<el-table-column sortable width="140" prop="gatewayName" label="接口">
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</template>
</el-col>
<el-col :span="12">
<template>
<el-tabs v-model="activeTabRight" type="card" @tab-click="handleTabLeft">
<el-tab-pane label="持仓" name="position">
<el-table :data="position" :height="table_height" border style="width: 100%">
<el-table-column fixed sortable prop="symbol" width="80" label="合约代码">
</el-table-column>
<el-table-column sortable width="80" prop="" label="名称">
</el-table-column>
<el-table-column sortable width="80" prop="direction" label="方向">
</el-table-column>
<el-table-column sortable width="80" prop="position" label="持仓">
</el-table-column>
<el-table-column sortable width="80" prop="ydPosition" label="昨持仓">
</el-table-column>
<el-table-column sortable width="80" prop="frozen" label="冻结量">
</el-table-column>
<el-table-column sortable width="80" prop="price" label="价格">
</el-table-column>
<el-table-column sortable width="80" prop="gatewayName" label="持仓盈亏">
</el-table-column>
<el-table-column sortable width="80" prop="askPrice3" label="接口">
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="资金" name="money">
<el-table :data="account" :height="table_height" width="80" border style="width: 100%">
<el-table-column fixed sortable width="80" prop="accountID" label="账户">
</el-table-column>
<el-table-column sortable width="80" prop="preBalance" label="昨结">
</el-table-column>
<el-table-column sortable width="80" prop="balance" label="净值">
</el-table-column>
<el-table-column sortable width="80" prop="available" label="可用">
</el-table-column>
<el-table-column sortable width="80" prop="commission" label="手续费">
</el-table-column>
<el-table-column sortable width="80" prop="margin" label="保证金">
</el-table-column>
<el-table-column sortable width="80" prop="closeProfit" label="平仓盈亏">
</el-table-column>
<el-table-column sortable width="80" prop="positionProfit" label="持仓盈亏">
</el-table-column>
<el-table-column sortable width="80" prop="gatewayName" label="接口">
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</template>
</el-col>
</el-row>
</el-col>
</el-row>
</el-main>
</el-container>
</el-tab-pane>
<el-tab-pane label="查询" name="search" v-loading="loading.contract">
<template>
<el-table :data="contract" stripe :height="window.innerHeight" style="width: 100%">
<el-table-column prop="symbol" label="合约代码"></el-table-column>
<el-table-column prop="exchange" label="交易所"></el-table-column>
<el-table-column prop="vtSymbol" label="vt系统代码"></el-table-column>
<el-table-column prop="name" label="日期"></el-table-column>
<el-table-column prop="productClass" label="合约类型"></el-table-column>
<el-table-column prop="size" label="大小"></el-table-column>
<el-table-column prop="priceTick" label="最小价格变动"></el-table-column>
<el-table-column fixed="right" label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">订阅</el-button>
</template>
</el-table-column>
</el-table>
</template>
</el-tab-pane>
<el-tab-pane label="CTA" name="cta">
<el-main style="padding:8px 0px;">
<el-row>
<el-col :span='24'>
<el-button type="primary" plain @click="doOnLoad">加载策略</el-button>
<el-button type="success" plain>全部初始化</el-button>
<el-button type="danger" plain>全部启动</el-button>
<el-button type="warning" plain>全部停止</el-button>
<el-button type="info" plain>保持持仓</el-button>
</el-col>
<el-col :span='24' class="cta-frame cta-frame__top" :style="{ height: topFrame}" v-loading="loading.strategy">
<div class="cta-frame__top_section" v-for="item,index in strategy">
<div class="itemName">{{item.name}}</div>
<el-button size="mini" :id="item.name" round @click="doAction(item.name,'init')">初始化</el-button>
<el-button size="mini" round @click="doAction(item.name,'start')">启动</el-button>
<el-button size="mini" round @click="doAction(item.name,'stop')">停止</el-button>
<template>
<el-table :data="[item.par]" stripe style="width: 100%; margin-bottom: 12px;">
<el-table-column :pro="subindex" :label="subindex" v-for="(subitem, subindex) in item.par" width="120">
<template scope="scope">
{{[item.par][scope.$index][subindex]}}
</template>
</el-table-column>
</el-table>
</template>
<template>
<el-table :data="[item.var]" stripe style="width: 100%">
<el-table-column :pro="subindex" :label="subindex" v-for="(subitem, subindex) in item.var" width="120">
<template scope="scope">
{{[item.var][scope.$index][subindex]}}
</template>
</el-table-column>
</el-table>
</template>
</div>
</el-col>
<el-col :span='24' :style="{ height: topFrame}">
<el-table :data="ctaLog" height="200" border style="width: 100%">
<el-table-column fixed width="120" sortable prop="logTime" label="时间">
</el-table-column>
<el-table-column sortable prop="logContent" label="内容">
</el-table-column>
</el-table-column>
</el-table>
</el-col>
</el-row>
</el-main>
</el-tab-pane>
</el-tabs>
</template>
</div>
</body>
<!-- 先引入 Vue -->
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<!-- 引入组件库 -->
<script src="https://cdn.bootcss.com/element-ui/2.1.0/index.js"></script>
<script>
var socket = io.connect("http://101.37.23.188:5000", { transports: ['websocket'] });
var _strategy = new Object()
new Vue({
el: '#app',
data: function() {
return {
table_height: (window.innerHeight - 70) / 3 - 15 || 250,
winHeight:window.innerHeight,
topFrame:window.innerHeight*2/3 - 65 + "px",
bottomFrame:window.innerHeight/3 - 65 + "px",
leftTradeHeight: (window.innerHeight - 50) + 'px',
selected_data: [],
form: {
volume: 1,
vtSymbol: '',
lastPrice: '',
direction: '',
offset: '',
priceType: '',
},
formRules: {
vtSymbol: [
{ required: true, message: '请输入代码', trigger: 'blur' }
],
lastPrice: [
{ required: true, message: '请输入代码', trigger: 'blur' }
],
direction: [
{ required: true, message: '请选择方向类型', trigger: 'change' }
],
offset: [
{ required: true, message: '请输入开平', trigger: 'change' }
],
priceType: [
{ required: true, message: '请输入价格类型', trigger: 'change' }
]
},
eAccount: [],
eTick: [],
tickObj: {},
eContract: [],
connection: '未连接',
activeTab: "home",
activeTabLeft: 'trade',
activeTabRight: 'position',
log: [], //日志
position: [], //持仓
order: [], //委托
trade: [], //成交
account: [], //资金
error: [], //错误
contract: [], //合约查询结果
leftTrade: {}, //存放左侧交易区显示数据
config: {}, //存放token等数据
strategy: {}, //策略名
ctaLog:[],
loading: {
subScribe: false,
order: false,
contract: false,
strategy:false,
},
}
},
created: function() {
this.gToken()
this.gAccount()
this.gConnectionStatus()
this.gTick()
this.gLog()
this.gPosition()
this.gError()
this.gOrder()
this.gTrade()
const that = this;
that.onLoadInfo('account', 'account')
that.onLoadInfo('trades', 'trade')
that.onLoadInfo('position', 'position')
that.onLoadInfo('log', 'log')
that.onLoadInfo('error', 'error')
},
methods: {
doAction(e,type){
let name = e, that = this, info="";
switch(type){
case "init": info = "初始化"
break;
case "stop": info = "停止"
break;
case "start": info = "启动"
break;
}
axios.post("http://101.37.23.188:5000/ctastrategy/" + type,{
name:name,
token:this.config.token
})
.then(res=>{
if (res.data.result_code =="success") {
that.$message({ message: name + info + '成功', type: 'success' });
if (type == "start") {
that.gCtaStrategy()
}
}else{
that.$message({ message: name + info +'成功', type: 'fail' });
}
})
.catch(res=>{
that.$message({ message: name + info +'成功', type: 'fail' });
})
},
doOnLoad() {
const that = this;
let strategy = {};
that.loading.strategy = true;
axios.post('http://101.37.23.188:5000/ctastrategy/load', {
token: this.config.token
})
.then(res => {
if (res.data.result_code !== "success") {
that.$notify({ title: '警告', message: 'ctastrategy/load接口报错', type: 'warning', duration: 0, });
return;
} else {
let strategy = res.data.data;
strategy.forEach((item) => {
_strategy[item] = { name: item };
that.gParams(item)
that.gVar(item)
})
}
})
},
gVar(name) {
const that = this,
_var = new Object();
axios.get("http://101.37.23.188:5000/ctastrategy/var?name=" + name + "&token=" + this.config.token)
.then(res => {
if (res.data.result_code !== "success") {
that.$notify({ title: '警告', message: 'ctastrategy/var接口报错', type: 'warning', duration: 0, });
return;
} else {
_strategy[name]['var'] = res.data.data;
that.strategy = _strategy;
that.loading.strategy = false;
}
})
.catch(res => {
that.$notify({ title: '警告', message: 'ctastrategy/var接口报错', type: 'warning', duration: 0, });
})
},
gCtaStrategy() {
let that = this;
socket.on("eCtaStrategy.", function(data) {
let name = data.name;
delete data['name'];
that.strategy[name]['var'] = data;
});
},
gCtaLog() {
let that = this,
logObj = new Object();
socket.on("eCtaLog", function(data) {
logObj[data.logTime] = data
that.ctaLog = that.ctaLog.concat(Object.values(logObj)).reverse()
});
},
gParams(name) {
const that = this;
axios.get("http://101.37.23.188:5000/ctastrategy/param?name=" + name + "&token=" + this.config.token)
.then(res => {
if (res.data.result_code !== "success") {
that.$notify({ title: '警告', message: 'ctastrategy/param接口报错', type: 'warning', duration: 0, });
return;
} else {
_strategy[name]['par'] = res.data.data;
that.strategy = _strategy;
that.loading.strategy = false;
}
})
.catch(res => {
console.log(res)
that.$notify({ title: '警告', message: 'ctastrategy/param接口报错', type: 'warning', duration: 0, });
})
},
onLoadInfo(apiName, dataArr) {
const that = this;
if (this.config.token !== undefined) {
gInfo(apiName, this.config.token)
} else {
axios.get('http://101.37.23.188:5000/token?username=test&password=test', {
})
.then(function(res) {
if (res.status == 200 && res.data.result_code == "success") {
let token = res.data.data
gInfo(apiName, token)
} else {
that.$notify({ title: '警告', message: 'token获取失败', type: 'warning', duration: 0, });
}
})
.catch(function(res) {
that.$notify({ title: '警告', message: 'token获取失败', type: 'warning', duration: 0, });
});
}
function gInfo(apiName, token) {
axios.get("http://101.37.23.188:5000/" + apiName + "?token=" + token)
.then(res => {
if (res.data.result_code == "success") {
that[dataArr] = that[dataArr].concat(res.data.data).reverse()
} else {
that.$notify({ title: '警告', message: '服务异常获取信息失败1', type: 'warning', duration: 3000, });
}
})
.catch(res => {
that.$notify({ title: '警告', message: '服务异常获取信息失败2', type: 'warning', duration: 3000, });
})
}
},
onSubmit(e) {
this.loading.order = true;
const that = this;
axios.post('http://101.37.23.188:5000/order', {
vtSymbol: this.form.vtSymbol,
price: this.form.lastPrice,
volume: this.form.volume,
priceType: this.form.priceType,
direction: this.form.direction,
offset: this.form.offset,
token: this.config.token,
})
.then(function(res) {
that.loading.order = false;
if (res.data.result_code == "success") {
that.$message({ message: '发单成功', type: 'success' });
} else {
that.$notify({ title: '警告', message: '服务异常,发单失败', type: 'warning', duration: 3000, });
}
})
.catch(function(err) {
that.loading.order = false;
that.$notify({ title: '警告', message: '服务异常,发单失败', type: 'warning', duration: 3000, });
});
},
onSubscribe(target) {
const that = this;
if (typeof(target) !== "object") {
var _vtSymbol = target
} else {
var _vtSymbol = this.form.vtSymbol
}
if (this.config.token == undefined || this.config.token == "") {
this.gToken()
}
if (_vtSymbol == undefined || _vtSymbol == "") {
return this.$alert('请输入代码', '提示', {
confirmButtonText: '确定',
});
} else {
this.loading.subScribe = true;
axios.post("http://101.37.23.188:5000/tick", {
vtSymbol: _vtSymbol,
token: this.config.token
})
.then(res => {
that.loading.subScribe = false;
if (res.data.result_code == "success") {
let target = _vtSymbol
that.clickTick(target)
that.form.vtSymbol = target;
that.$message({ message: '订阅成功', type: 'success' });
} else {
that.$notify({ title: '警告', message: '订阅失败', type: 'warning', duration: 3000, });
}
})
.catch(res => {
that.loading.subScribe = false;
that.$notify({ title: '警告', message: '服务异常,订阅失败', type: 'warning', duration: 3000, });
})
}
},
dOrder(e) {
let vtOrderID = e.vtOrderID,
that = this;
axios.delete("http://101.37.23.188:5000/order?vtOrderID=" + vtOrderID + "&token=" + this.config.token)
.then(res => {
if (res.data.result_code == "success") {
that.$message({ message: '撤单已提交', type: 'success' });
} else {
that.$notify({ title: '警告', message: '服务异常,撤单提交失败', type: 'warning', duration: 2000, });
}
})
.catch(res => {
that.$notify({ title: '警告', message: '服务异常,撤单提交失败', type: 'warning', duration: 2000, });
})
},
gToken() {
const that = this;
axios.get('http://101.37.23.188:5000/token?username=test&password=test')
.then(function(res) {
if (res.status == 200 && res.data.result_code == "success") {
that.config.token = res.data.data
that.gGateway(res.data.data)
} else {
that.$notify({ title: '警告', message: 'token获取失败', type: 'warning', duration: 0, });
}
})
.catch(function(err) {
that.$notify({ title: '警告', message: 'token获取失败', type: 'warning', duration: 0, });
});
},
handleClick(row) {
this.onSubscribe(row.vtSymbol)
},
handleTab(tab) {
const that = this;
that.loading.contract = true;
if (tab.name == "search") {
this.gContract()
}else if(tab.name == "cta"){
this.judgeIfStrategy()
this.gCtaLog()
}
},
judgeIfStrategy(){
let that = this;
axios.get("http://101.37.23.188:5000/ctastrategy/name?token="+this.config.token)
.then(res=>{
let nameArray = res.data.data;
nameArray.forEach(function(item){
_strategy[item] = { name: item };
that.gParams(item)
that.gVar(item)
})
})
.catch(res=>{
console.log(res)
})
},
gContract(){
const that = this;
if (that.contract.length == 0) {
axios.get("http://101.37.23.188:5000/contract?token=" + this.config.token)
.then(res => {
that.loading.contract = false;
if (res.data.result_code == "success") {
that.contract = res.data.data
} else {
that.$notify({ title: '警告', message: '连接异常', type: 'warning', duration: 4500, });
}
})
.catch(res => {
that.$notify({ title: '警告', message: '连接异常', type: 'warning', duration: 4500, });
})
}
},
gGateway(token) {
axios.post('http://101.37.23.188:5000/gateway', {
token: token,
gatewayName: 'CTP'
})
.then(function(res) {
})
.catch(function(err) {
});
},
gTick(target) {
let that = this,
tick = new Object(),
tickObj = new Object();
socket.on("eTick.", function(data) {
tick[data.symbol] = data
that.tickObj = tick
that.eTick = Object.values(tick).reverse()
});
},
clickTick(e) {
let that = this,
tick = new Object(),
tickObj = new Object(),
target = e.vtSymbol || e;
if (that.tickObj[target] !== undefined) {
that.form.lastPrice = that.tickObj[target].lastPrice
}
that.form.vtSymbol = target
socket.on("eTick.", function(data) {
that.leftTrade = that.tickObj[target]
that.leftTrade.priceRatio = ((that.tickObj[target].lastPrice / that.tickObj[target].preClosePrice) - 1).toFixed(2) + "%"
// if (that.tickObj[target] !== undefined) {
// if (that.tickObj[target].lastPrice == undefined) {
// that.form.lastPrice = that.tickObj[target].lastPrice
// }
// }
});
},
gOrder() {
let that = this,
orderObj = new Object();
socket.on("eOrder.", function(data) {
orderObj[data.orderID] = data
that.order = Object.values(orderObj).reverse()
});
},
gAccount() {
let that = this,
accounts = new Object();
socket.on("eAccount.", function(data) {
accounts[data.orderID] = data
that.account = that.account.concat(Object.values(accounts)).reverse()
});
},
gPosition() {
let that = this,
positions = new Object();
socket.on("ePosition.", function(data) {
positions[data.symbol] = data
that.position = that.position.concat(Object.values(positions)).reverse()
});
},
gTrade() {
let that = this,
trades = new Object();
socket.on("eTrade.", function(data) {
trades[data.orderID] = data
that.trade = that.trade.concat(Object.values(trades)).reverse()
});
},
gError() {
let that = this,
errObj = new Object();
socket.on("eError.", function(data) {
errObj[data.errorTime] = data
that.error = that.error.concat(Object.values(errObj)).reverse()
// that.error = Object.values(errObj).reverse()
});
},
gLog() {
let that = this,
logObj = new Object();
socket.on("eLog.", function(data) {
logObj[data.logTime] = data
that.log = that.concat(Object.values(logObj)).reverse()
});
},
handleTabLeft(tab, event) {
},
handleTabRight(tab, event) {
},
gConnectionStatus() {
const that = this;
socket.on('disconnect', function() {
that.connection = '已断开'
that.$notify({
title: '警告',
message: '服务器连接已断开',
type: 'warning',
duration: 4500,
});
});
socket.on('connect_failed', function() {
that.connection = '连接失败'
that.$notify({
title: '警告',
message: '服务器连接失败',
type: 'warning',
duration: 4500,
});
});
socket.on('connect', function() {
that.connection = '已连接'
that.$notify({
title: '成功',
message: '服务器连接成功',
type: 'success',
duration: 2000,
});
});
socket.on('connecting', function() {
that.connection = '正在连接'
});
socket.on('error', function() {
that.connection = '连接错误'
that.$notify({
title: '警告',
message: '服务器连接错误',
type: 'warning',
duration: 4500,
});
});
},
}
})
</script>
</html>