js+python websocket实时推数据

js与python 通过websocket通信

## user.html

{% extends "monitor.html" %}
{% load staticfiles %}
<head>

</head>
{% block title %}仿真策略监控{% endblock %}

{% block styles %}
    <style>

        th {
            text-align: center;
        }

        label {
            width: 100px;
        }

        input, select {
            width: 160px;
            height: 24px;
            background: #0F0F0F;
            border: 1px solid #3C3C3C;
            border-radius: 1px;
        }

        button {
            border: none;
        }

        thead {
            background-color: #444;
        }

        .bootstrap-table {
            border-style: solid;
            border-width: 3px;
        }

        .pagination-info {
            display: none
        }

        .page-list {
            display: none
        }

        #sse {
            color: white;
        }

        #startstg .modal-body {
            background-color: #282923;
            padding: 0px;
        }

        {#无数据时鼠标悬浮的背景颜色#}
        .table-hover > tbody > tr:hover {
            background-color: #444444;
            cursor: pointer;
        }

        {#无数据时的奇数背景颜色#}
        {#        .table-striped > tbody > tr:nth-of-type(odd) {#}
        {#            background-color: transparent;#}
        {#        }#}

        #StgFileShow, #ConFileShow {
            background-color: #282923;
            color: #90918b;
            border-width: 0px;
            width: 448px;
            height: 100%;
        }

        #stg_check {
            padding: 10px;
        }

        .row {
            margin-top: 10px;
        }


        .left {
            width: 60%;
            height: 400px;
            float: left;
        }

        .right {
            width: 37%;
            height: 400px;
            float: left;
        {#margin-right: 30px;#}
        }

        .buttom {
            width: 97%;
            height: 400px;
            float: left;
            margin-top: 90px;
        }

        {#tab表头的选中的样式#}
        .nav-tabs-custom > .nav-tabs > li.active > a, .nav-tabs-custom > .nav-tabs > li.active:hover > a {
            background-color: red;
            color: white;
        }

        {#tab样式#}
        .nav-tabs-custom > .nav-tabs > li {
            border-top: transparent;
            margin-bottom: -2px;
            margin-right: 2px;
        }

        .nav-tabs > li {
            float: left;
            margin-bottom: -1px;
        }

        .nav > li > a {
            position: relative;
            display: block;
            padding: 4px 20px;
        }

        {#tab头的位置及边框颜色透明#}
        .nav-tabs-custom > .nav-tabs {
            border-bottom-color: rgba(0, 0, 0, 0.2);
            border-top-right-radius: 3px;
            border-top-left-radius: 3px;
            margin-left: 10px;
        }

        {#tab中的a标签悬浮样式#}

        .nav-tabs-custom > .nav-tabs > li > a, .nav-tabs-custom > .nav-tabs > li > a:hover {
            background: rgba(255, 255, 255, .15);
            margin: 0;
        }

        .nav-tabs-custom > .nav-tabs > li > a {
            color: #d2d6de;
            border-radius: 0;
        }


        .simcheck {
            float: left;
            margin-top: 15px;
            margin-left: 10px
        }

        .packheadiv {
            float: left;
            margin-top: 15px;
            margin-left: 10px
        }

        .cancelheadiv {
            float: left;
            margin-top: 15px;
            margin-left: 10px
        }

        .simcheckhead, .simHead, .packHead {
            color: white;
            margin-left: 30px;
        }

        .cancelheadiv, .packheadiv, .traheadiv {
            margin-left: 30px;
        }

        .bootstrap-table .fixed-table-container .table {
            width: 100%;
            margin-bottom: 0 !important;
            color: #939393;
        }

        .fixed-table-toolbar {
            background-color: #141414;
        }

        .checksearch, .packsearch, .simsearch {
            width: 87px;
            height: 26px;
            background: #3C3C3C;
            border-radius: 3px;

        }

        .cancelorder {
            width: 119px;
            height: 28px;
            background: inherit;
            background-color: rgba(255, 204, 153, 1);
            box-sizing: border-box;
            border-width: 1px;
            border-style: solid;
            border-color: rgba(121, 121, 121, 1);
            border-radius: 5px;
            -moz-box-shadow: none;
            -webkit-box-shadow: none;
            box-shadow: none;
            color: #2B2B2B;
            margin-left: 15%;
            cursor: pointer;
        }

        tr.activetable, input.activetable {
            background-color: white;
            width: 114px;
            height: 30px;
        }


    </style>
{% endblock %}

{% block content %}
    <section class="content-header" style="background-color: #000000">
        <h1 style="color: #FFFFFF">
            仿真策略监控
            <small>{{ allHtml.title }}</small>
        </h1>
    </section>
    <div class="modal fade" id="upmodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-dialog" style="width: 450px;">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span></button>
                    <h4 class="modal-title">上传策略</h4>
                </div>
                <div class="modal-body" style="padding: 30px;height:auto">
                    <form>
                        <div style="margin-top:3%; display: block">
                            <label>策略名称</label>
                            <input class="opts form-control" id="confirmpwd" name="confirmpwd" type="text"
                                   placeholder="确认密码">
                        </div>
                        <div style="margin-top:3%"><label>指定服务器</label>
                            <select class="opts form-control" id="isactive" name="isactive">
                                <option name="isactive" value="1">
                                    服务器1
                                </option>
                                <option name="isactive" value="2">
                                    服务器2
                                </option>
                            </select>
                        </div>
                        <div style="margin-top:3%"><label>策略组</label>
                            <select class="opts form-control" id="stgroup" name="stgroup">
                                <option name="isactive" value="1">
                                    做市策略
                                </option>
                                <option name="isactive" value="2">
                                    CTA策略
                                </option>
                                <option name="isactive" value="3">
                                    算法策略
                                </option>
                            </select>
                        </div>
                        <div style="margin-top:3%"><label>选择文件</label>
                            <input class="opts form-control" id="maxlogined" name="maxlogined" type="file"
                                   placeholder="选择文件">
                        </div>
                        <div style="margin-top:3%"><label>策略参数</label>

                            <table style="background-color: white">
                                <thead>
                                <tr class="activetable">
                                    <th>
                                        操作
                                    </th>
                                    <th>
                                        参数名*
                                    </th>
                                    <th>
                                        参数值*
                                    </th>
                                    <th>
                                        参数描述
                                    </th>
                                </tr>
                                </thead>
                                <tbody id="tb1">
                                <tr class="activetable">
                                    <td>
                                        <span style="padding:3px;cursor: pointer" class="btn-success small"
                                              onclick="new_col('tb1')">新增行
                                        </span>
                                    </td>
                                    <td>
                                        <input class="activetable" name="stg_val">
                                    </td>
                                    <td>
                                        <input class="activetable" name="stg_choices">
                                    </td>
                                    <td>
                                        <input class="activetable" name="stg_desc">
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                        <div style="margin-top:3%">
                            <span style="margin-left:10%;cursor:pointer;padding:5px" class="btn-primary"
                                  onclick="sub(gets)">提交</span>
                            <span style="margin-left:60%;cursor:pointer;padding:5px" class="btn-success"
                                  onclick="quit__()">取消</span>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <div class="modal fade" id="editstg" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-dialog" style="width: 450px;">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span></button>
                    <h4 class="modal-title">修改策略参数</h4>
                </div>
                <div class="modal-body" style="padding: 30px;height:auto">
                    <form>
                        <div style="margin-top:3%"><label>参数名</label>
                            <input type="text" id="paraname" readonly>
                        </div>
                        <div style="margin-top:3%"><label>参数值</label>
                            <input type="text" id="paravalue">
                        </div>
                        <div style="margin-top:3%"><label>描述</label>
                            <input type="text" id="paradesc">
                        </div>

                        <div style="margin-top:3%">
                            <span style="margin-left:10%;cursor:pointer;padding:5px" class="btn-primary"
                                  onclick="sub(gets)">提交</span>
                            <span style="margin-left:60%;cursor:pointer;padding:5px" class="btn-success"
                                  onclick="quit__()">取消</span>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <!-- Main content -->
    <section class="content" style="background-color: #000000">
        <div class="row">
            <div class="col-xs-12">
                <div class="nav-tabs-custom left" style="background-color: #000000">
                    <ul class="nav nav-tabs">
                        <li class="active"><a href="#fa-simapproval" onclick="tabs(1)" data-toggle="tab">策略列表</a></li>
                    </ul>
                    <div class="tab-content" style="background-color: #000000">
                        <!--仿真审批-->
                        <div class="tab-pane active mailbox-messages" id="fa-simapproval">
                            <div class=" mailbox-messages">
                                <div class="cancelheadiv" style="margin-left: 25px"></div>
                                <table id="toolbar"></table>
                                <table class="table table-bordered table-striped table-hover" id="RuleTable">
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="nav-tabs-custom right" style="background-color: #000000">
                    <ul class="nav nav-tabs">
                        <li id="stgpara"><a href="#fa-stgpara" onclick="tabs(1)" data-toggle="tab">策略参数</a></li>
                        <li id="stgindic"><a href="#fa-stgindic" onclick="tabs(2)" data-toggle="tab">策略指标</a></li>
                    </ul>
                    <div class="tab-content" style="background-color: #000000">
                        <!--策略参数-->
                        <div class="tab-pane mailbox-messages" id="fa-stgpara">
                            <div class=" mailbox-messages">
                                <table id="toolbar"></table>
                                <div class="cancelheadiv" style="margin-left: 25px">
                                </div>
                                <table class="table table-bordered table-striped table-hover" id="StgparaTable">
                                </table>
                            </div>
                        </div>
                        <!--策略指标-->
                        <div class="tab-pane mailbox-messages" id="fa-stgindic">
                            <div class=" mailbox-messages">
                                <table id="toolbar"></table>
                                <div class="cancelheadiv" style="margin-left: 25px">
                                </div>
                                <table class="table table-bordered table-striped table-hover" id="StgdicTable">
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="nav-tabs-custom buttom" style="background-color: #000000">
                    <ul class="nav nav-tabs">
                        <li><a href="#fa-stgmm" onclick="btabs(1)" data-toggle="tab">做市类策略</a></li>
                        <li><a href="#fa-stgcta" onclick="btabs(2)" data-toggle="tab">CTA类策略</a></li>
                    </ul>
                    <div class="tab-content stginfo" style="background-color: #000000">
                        <!--做市类策略-->
                        <div class="tab-pane mailbox-messages" id="fa-stgmm">
                            <div class=" mailbox-messages">
                                <table id="toolbar"></table>
                                <div class="cancelheadiv" style="margin-left: 25px">
                                </div>
                                <table class="table table-bordered table-striped table-hover" id="StgMMTable">
                                </table>
                            </div>
                        </div>
                        <!--CTA类策略-->
                        <div class="tab-pane mailbox-messages" id="fa-stgcta">
                            <div class=" mailbox-messages">
                                <table id="toolbar"></table>
                                <div class="cancelheadiv" style="margin-left: 25px">
                                </div>
                                <table class="table table-bordered table-striped table-hover" id="StgCtaTable">
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <div id="sse">
        <form id="userLogin">
            <p>用户名:<input type="text" id="uname"></p>
            <p>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码:<input type="password" id="upwd"></p>
            <p><input type="button" value="登 录" onclick="sendMsg_login()"></p>
        </form>
        <p>
        <p>合约:<input type="text" id="instrumentID" value="T2009"></p>
        <input type="button" onclick="ws.SubscribeMarketData($('#instrumentID').val())" value="订阅行情"/>
        <h2>用户登录查看到的数据</h2>
        <div id="console" style="width: 100%;height:200px;">


        </div>
        </p>

    </div>

{% endblock %}

{% block scripts %}


    <script type="text/javascript">
		
		//页面加载后就调用
        {#import lo from "../../../commonStatic/bower_components/moment/src/locale/lo";#}

        {#$(function () {#}
        {#    alert("qew")#}
        {# })#}

        var timer, clickFlag, stgtype = false;//外部变量,这三个变量是定时器是否存在的标志
        //初始化策略列表
        $("#RuleTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            // 策略列表table
            columns: [{
                field: 'RuleID',
                title: '策略ID'
            }, {
                field: 'RuleName',
                title: '策略名称'
            }, {
                field: 'LServer',
                title: '指定服务器',
                {#formatter: function (value, row, index) {#}
                {#    $.post("{% url 'trade:serverfind' %}", {"ruleid": row.RuleID}, function (r) {#}
                {#        if (r){#}
                {#            console.log("123adce", r)#}
                {#            return r#}
                {#        }#}
                {#    })#}
                {# }#}
            }, {
                field: 'RuleRunStatus',
                title: '运行状态',
                formatter: function (value, row, index) {
                    if (value === "0") {
                        return "停止"
                    } else if (value === "1") {
                        return "启动"
                    } else {
                        return value
                    }
                }
            }, {
                field: 'LOption',
                title: '操作',
                formatter: function (value, row, index) {
                    if (row.RuleRunStatus === "1") {
                        var start = "<span onclick=\"startstg('" + row.RuleID + "')\" class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' disabled='disabled'> <i class='fa'></i>启动</span> ";
                        var end = "&nbsp<span onclick=\"endstg('" + row.RuleID + "')\" type='button' class='btn btn-danger btn-xs btn-flat btn_operation'> <i class='fa'></i>停止</span>";
                    } else if (row.RuleRunStatus === "0") {
                        var start = "<span onclick=\"startstg('" + row.RuleID + "')\" class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' > <i class='fa'></i>启动</span> ";
                        var end = "&nbsp<span onclick=\"endstg('" + row.RuleID + "')\" type='button' class='btn btn-danger btn-xs btn-flat btn_operation'disabled='disabled'> <i class='fa'></i>停止</span>";
                    }
                    return start + end + "&nbsp<span onclick=\"del_('" + row.RuleID + "')\" type='button' class='btn btn-primary btn-xs btn-flat btn_operation'> <i class='fa'></i>人工录入</span>";
                }
            },
                {
                    field: 'LRisk',
                    title: '风控',
                }],
            onClickRow: function (row, $element, field) {
                {#console.log(rules)#}
                //当前行的父元素tbody下的所有tr移除样式类
                $element.parent().children().removeClass("onclickrow")
                $element.addClass("onclickrow")
                var ruleid = row.RuleID
                //点击一行数据,初始化策略参数和策略指标
                RulePropIndic(ruleid)
                //刚开始需要把上次的定时器取消掉,然后再进行定时任务。
                if (clickFlag) {
                    clearInterval(timer)
                }
                clickFlag = true;
                timer = setInterval(function () {
                    //先移除所有的数据,然后再append
                    $('#StgparaTable').bootstrapTable('removeAll');
                    $('#StgdicTable').bootstrapTable('removeAll');
                    for (let key in ruleProps) {
                        //策略参数
                        if (key.startsWith(ruleid + "prop")) {
                            $('#StgparaTable').bootstrapTable('append', ruleProps[key]);
                        }
                        //策略指标
                        else if (key.startsWith(ruleid + "indic")) {
                            $('#StgdicTable').bootstrapTable('append', ruleProps[key]);
                        }
                    }
                    var clickFlag = false
                }, 2000)
                //关闭定时器
                {#clearInterval(timer)#}
            }
        })

        //初始化策略参数
        $("#StgparaTable").bootstrapTable('destroy').bootstrapTable({
            {#uniqueId: "RuleID" + "prop_" + "PropKey",#}
            // 策略列表table
            columns: [{
                field: 'RuleID',
                title: '策略ID',
                visible: false
            }, {
                field: 'PropKey',
                title: '参数名'
            }, {
                field: 'PropValue',
                title: '参数值'
            }, {
                field: 'Description',
                title: '描述',
            }, {
                field: 'POption',
                title: '操作',
                formatter: function (value, row, index) {
                    return "<span onclick=\"modify('" + row.RuleID  + "'" + "," + "'" + row.PropKey + "'"+
                        ","+ "'" +row.PropValue+"'"+"," + "'" + row.Description+"')\" class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' data-target='#startstg'> <i class='fa'></i>编辑</span> "
                }
            }]
        })

        //初始化策略指标
        $("#StgdicTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            // 策略列表table
            columns: [{
                field: 'RuleID',
                title: '策略ID',
                visible: false
            }, {
                field: 'IndicatorKey',
                title: '指标名'
            }, {
                field: 'IndicatorValue',
                title: '指标值'
            }, {
                field: 'Description',
                title: '指标描述',
            }]
        })

        //初始化做市策略
        $("#StgMMTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            // 做市策略table
            columns: [
                //第一行表头
                [{
                    field: 'RuleID',
                    title: '',
                    {#visible: false#}
                }, {
                    field: 'mm',
                    title: '做市券盘口',
                    colspan: 2
                }, {
                    field: 'hedge',
                    title: '对冲券盘口',
                    colspan: 2
                }, {
                    field: '',
                    title: '',
                    colspan: 2
                }, {
                    field: "my",
                    title: "我方报价",
                    colspan: 2
                }, {
                    field: '',
                    title: '',
                    colspan: 2
                }],
                //第二行表头
                [{
                    field: "RuleName",
                    title: "策略名称"
                }, {
                    field: "bid_mm",
                    title: "Bid"
                }, {
                    field: "ofr_mm",
                    title: "Ofr"
                }, {
                    field: "bid_hedge",
                    title: "Bid"
                }, {
                    field: "ofr_hedge",
                    title: "Ofr"
                }, {
                    field: "spread",
                    title: "合理利差"
                }, {
                    field: "offset",
                    title: "偏移"
                }, {
                    field: "bid_my",
                    title: "Bid"
                }, {
                    field: "ofr_my",
                    title: "Ofr"
                }, {
                    field: "position",
                    title: "持仓"
                }, {
                    field: "is_broken",
                    title: "断腿警告"
                }]
            ]
        })

        //初始化cta策略
        $("#StgCtaTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            // CTA策略table
            columns: [{
                field: "RuleName",
                title: "策略名称"
            }, {
                field: "indicator1",
                title: "指标1"
            }, {
                field: "indicator2",
                title: "指标2"
            }, {
                field: "trade_time",
                title: "最新成交时间"
            }, {
                field: "yield",
                title: "收益率"
            }, {
                field: "high",
                title: "高"
            }, {
                field: "low",
                title: "低"
            }, {
                field: "decision",
                title: "决策点"
            }, {
                field: "trigger",
                title: "触发点"
            },
                {
                    field: "direction",
                    title: "方向"
                },
                {
                    field: "position",
                    title: "持仓"
                },
                {
                    field: "volume_left",
                    title: "待执行量"
                },
                {
                    field: "ytm_signal",
                    title: "信号价格"
                },
                {
                    field: "ytm_limit",
                    title: "限价"
                }]
        })

        //rules用于存储 策略列表和不同类型的策略, ruleprops用于存储策略参数和策略指标
        var rules = {}, ruleProps = {};
        var idsarry = []; //windows-server, 47.102.219.52:9000
        var ws = $.trade("ws://127.0.0.1:9000/", {//
            OnFrontConnected: function () {
                $("#console").append("<br/>TD连接成功");
            },
            OnFrontDisconnected: function () {
                $("#console").append("<br/>TD已断开");
            },
            OnRspUserLogin: function (r) {
                //{TID: data:{},RspInfoField:{ErrorID:“”,ErrorMsg:“”}
                if (r.RspInfoField.ErrorID == 0) {
                    $("#console").append("<br/>" + r.data.CustomerID + " 交易登录成功");
                    user.CustomerID = r.data.CustomerID;
                } else
                    $("#console").append("<br />交易登录失败:" + r.RspInfoField.ErrorMsg);
            },
            OnRspError: function (r) {
                $("#console").append("<br/>" + r.RspInfoField.ErrorID + ":" + r.RspInfoField.ErrorMsg);
            },
            OnRtnRule: function (r) {
                if (rules[r.data.RuleID] == undefined) {
                    if (r.data.RuleRunStatus == undefined) {
                        r.data.RuleRunStatus = 0;
                    }
                    $('#RuleTable').bootstrapTable('append', r.data);
                } else {
                    $('#RuleTable').bootstrapTable('updateRow', {
                        index: r.data.RuleID,
                        row: r.data
                    });
                }
                rules[r.data.RuleID] = r.data;
                rules[r.data.RuleID].RuleRunStatus = 0;
                {#ruleType[r.data.RuleID] = r.data#}

                $("#console").append("<br/>策略信息: " + r.data.RuleID + ":" + r.data.RuleName);
            },
            OnRtnRuleStatus: function (r) {
                rules[r.data.RuleID].RuleRunStatus = r.data.RuleRunStatus;
                if (rules[r.data.RuleID].RuleRunStatus == undefined) {
                    $('#RuleTable').bootstrapTable('append', r.data);
                } else {
                    $('#RuleTable').bootstrapTable('updateRow', {
                        index: r.data.RuleID,
                        row: r.data
                    });
                }
                $("#console").append("<br/>策略状态 " + r.data.RuleID + ":" + r.data.RuleRunStatus);
            },
            OnRtnRuleProp: function (r) {
                if (rules[r.data.RuleID] !== undefined) {
                    rules[r.data.RuleID][r.data.PropKey] = r.data.PropValue
                }
                ruleProps[r.data.RuleID + "prop" + "_" + r.data.PropKey] = r.data
                $("#console").append("<br/>策略参数:" + r.data.RuleID + ":" + r.data.PropKey + ":" + r.data.PropValue + ":" + r.data.Description);

            },
            OnRtnRuleIndicator: function (r) {
                if (rules[r.data.RuleID] !== undefined) {
                    rules[r.data.RuleID][r.data.IndicatorKey] = r.data.IndicatorValue
                }
                ruleProps[r.data.RuleID + "indic" + "_" + r.data.IndicatorKey] = r.data;
                $("#console").append("<br/>策略指标:" + r.data.RuleID + ":" + r.data.IndicatorKey + ":" + r.data.IndicatorValue + ":" + r.data.Description);
            },
            events: {
                say: function (e) {
                    alert(e.data.name); // 'foo'
                    alert(e.data.text); // 'baa'
                }
            }
        });

        function sendMsg_login() {
            var dt = {
                "Tid": 1111, "data": {
                    'CustomerID': '1001',
                    'Password': '123456',
                    'MacAddress': '',
                    'SubInstrumentMethod': '',
                    'IsRule': ''
                }
            };
            ws.ReqUserLogin("1001", "123456");
        }

        function submitit() {
            $('#rf').submit();
        }

        function tabs(n) {
            if (n == 1) {
                $('#fa-stgpara').addClass('active');
                $('#fa-stgindic').removeClass('active');
            } else {
                $('#fa-stgpara').removeClass('active');
                $('#fa-stgindic').addClass('active');
            }
        }

        //点击做事类策略或者CTA类策略
        function btabs(n) {
            initypestg()
            if (n == 1) {
                $('#fa-stgmm').addClass('active');
                $('#fa-stgcta').removeClass('active');
                clearInterval(stgtype)
                stgtype = setInterval(function () {
                    //先移除所有的数据,然后再append
                    $('#StgMMTable').bootstrapTable('removeAll');
                    $('#StgCtaTable').bootstrapTable('removeAll');
                    //bootstraptable渲染不同类型的策略
                    for (let key in rules) {
                        if (rules[key].hasOwnProperty("bid_mm")) {
                            $('#StgMMTable').bootstrapTable('append', rules[key]);
                        } else if (rules[key].hasOwnProperty("trigger")) {
                            $('#StgCtaTable').bootstrapTable('append', rules[key]);
                        }
                    }
                }, 2000)

            } else {
                $('#fa-stgmm').removeClass('active');
                $('#fa-stgcta').addClass('active');
                clearInterval(stgtype)
                stgtype = setInterval(function () {
                    //先移除所有的数据,然后再append
                    $('#StgMMTable').bootstrapTable('removeAll');
                    $('#StgCtaTable').bootstrapTable('removeAll');
                    //bootstraptable渲染不同类型的策略
                    for (let key in rules) {
                        if (rules[key].hasOwnProperty("bid_mm")) {
                            $('#StgMMTable').bootstrapTable('append', rules[key]);
                        } else if (rules[key].hasOwnProperty("trigger")) {
                            $('#StgCtaTable').bootstrapTable('append', rules[key]);
                        }
                    }
                }, 2000)
            }

        }

        //做事类策略或者cTa类策略的初始化
        function initypestg() {
            //先移除所有的数据,然后再append
            $('#StgMMTable').bootstrapTable('removeAll');
            $('#StgCtaTable').bootstrapTable('removeAll');
            //bootstraptable渲染做事类策略
            for (let key in rules) {
                if (rules[key].hasOwnProperty("bid_mm")) {
                    $('#StgMMTable').bootstrapTable('append', rules[key]);
                } else if (rules[key].hasOwnProperty("trigger")) {
                    $('#StgCtaTable').bootstrapTable('append', rules[key]);
                }
            }
        }


        function status(th) {
            var StgID = $(th).attr('id');
            var S = $(th).attr('status');
            Status = S.split('-')[0];
            EnvID = S.split('-')[1];
            $.post("{{url}}", {
                'StgID': JSON.stringify([StgID]),
                'Status': JSON.stringify([Status]),
                'EnvID': JSON.stringify([EnvID])
            }, function (r) {
                if (r) {
                    window.location.reload();
                }
            })
        }

        function RefreshIt() {
            var opt = {
                url: "{{url}}",
                silent: true,
                query: {
                    env: $('#env').val()
                }
            };
            $("#RuleTable").bootstrapTable('refresh', opt);
        }


        function pack(sid) {
            $.post('{{url}}', {'sid': sid}, function (r) {
                $("#packTable").bootstrapTable('refresh');
            })
        }

        //策略参数和策略指标的定时任务
        function RulePropIndic(ruleid) {
            //先移除所有的数据,然后再append
            $('#StgparaTable').bootstrapTable('removeAll');
            $('#StgdicTable').bootstrapTable('removeAll');
            for (let key in ruleProps) {
                //策略参数
                if (key.startsWith(ruleid + "prop")) {
                    $('#StgparaTable').bootstrapTable('append', ruleProps[key]);
                }
                //策略指标
                else if (key.startsWith(ruleid + "indic")) {
                    $('#StgdicTable').bootstrapTable('append', ruleProps[key]);
                }
            }

        }

        function new_col(idn) {
            var h = "<tr class='activetable'>" + '<td>' +
                '                                        <span style="padding:3px; cursor: pointer" class="btn-danger small"\n' +
                '                                              onclick="$(this).parent().parent().remove()">删除行' +
                '                                        </span>' +
                '                                    </td>' +
                "<td><input class='activetable' name='stg_val'></td>" +
                "</td>" +
                "<td><input class='activetable' name='stg_choices'></td>" +
                "<td><input class='activetable' name='stg_desc'></td>" +
                "</tr>";
            $('#' + idn).append($(h));
        };

        //上传列表模态框展示
        function uploadmodal() {
            $("#upmodal").modal("show")
        }

        //启动策略
        function startstg(id) {
            ws.ReqOptionStg("start", id);
        }

        //停止策略
        function endstg(id) {
            ws.ReqOptionStg("end", id);
        }

        //编辑策略参数
        function modify(id, key, value, desc) {
            ws.ReqStgPara(id, key, value, desc)

        }

    </script>
    <style>
        {#加载数据时的样式#}
        .bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {
            align-items: center;
            background: #141414;
            display: none;
            justify-content: center;
            position: absolute;
            bottom: 0;
            width: 100%;
            z-index: 1000;
        }

        {#bootstraptable表格布局样式#}
        .bootstrap-table .fixed-table-container .table {
            width: 90%;
            margin-bottom: 0 !important;
            margin: 0 auto;
            border: solid #444 !important
        }

        {#bootstraptable上边框#}
        .table-bordered {
            border: 1px solid transparent !important;
        }

        {#bootstraptable左侧边框#}
        .table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td {
            border: 1px solid rgba(255, 255, 255, .15);
        }


        {#每一个table的样式#}
        .bootstrap-table .fixed-table-container .table thead th .th-inner {
            padding: .75rem;
            vertical-align: bottom;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            border: 1px solid #444 !important;
        }

        .tab-content {
            height: 380px;
        }

        .stginfo {
            height: 400px;
        }

        .onclickrow {
            background-color: #444444;
        }
    </style>


{% endblock %}
            
            

////// websocket.js
/*
 * jQuery Web Sockets Plugin v0.0.4
 * https://github.com/dchelimsky/jquery-websocket
 * http://code.google.com/p/jquery-websocket/
 *
 * This document is licensed as free software under the terms of the
 * MIT License: http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2010 by shootaroo (Shotaro Tsubouchi).
 */
const TSS_DIALOG = 1;		//对话流
const TSS_PRIVATE = 2;		//会员私有流
const TSS_PUBLIC = 3;		//公共流
const TSS_QUERY = 4;		//查询
const TSS_USER = 5;		//交易员私有流

//用户启动策略请求
const FTD_TID_ReqOptionStg = 0x00002101;
//编辑策略参数请求
const FTD_TID_ReqStgPara = 0x00002102
//用户登录请求
const FTD_TID_ReqUserLogin = 0x00001001;
//用户登录响应
const FTD_TID_RspUserLogin = 0x00001002;
//用户退出请求
const FTD_TID_ReqUserLogout = 0x00001005;
//用户退出响应
const FTD_TID_RspUserLogout = 0x00001006;
//报单录入请求
const FTD_TID_ReqOrderInsert = 0x00003001;
//报单录入错误时响应
const FTD_TID_RspOrderInsert = 0x00003002;
//报单修改/撤单请求
const FTD_TID_ReqOrderAction = 0x00003003;
//报单修改/撤单错误时响应
const FTD_TID_RspOrderAction = 0x00003004;
//请求查询合约
const FTD_TID_ReqQryInstrument = 0x00002001;
//请求查询合约响应
const FTD_TID_RspQryInstrument = 0x00002002;
//请求查询债券
const FTD_TID_ReqQryBond = 0x00001109;
//请求查询债券响应
const FTD_TID_RspQryBond = 0x0000110A;
//查询债券期货和可交割券关系表
const FTD_TID_ReqQryBondFutureDeliverable = 0x00001105;
//债券期货和可交割券关系表回报
const FTD_TID_RspQryBondFutureDeliverable = 0x00001106;
//请求查询物理账号资金
const FTD_TID_ReqQryAccount = 0x00002005;
//请求查询物理账号资金响应
const FTD_TID_RspQryAccount = 0x00002006;
//请求查询物理账号持仓
const FTD_TID_ReqQryPosition = 0x00002007;
//请求查询物理账号持仓响应
const FTD_TID_RspQryPosition = 0x00002008;
//请求订阅行情
const FTD_TID_ReqSubMarketData = 0x00002009;
//请求退订行情
const FTD_TID_ReqUnSubMarketData = 0x0000200b;
//请求订阅行情BAR
const FTD_TID_ReqSubMarketDataBar = 0x0000200d;
//请求退订行情BAR
const FTD_TID_ReqUnSubMarketDataBar = 0x0000200e;
//请求订阅新本币平台行情
const FTD_TID_ReqSubCFETSMarketData = 0x00001130;
//请求退订新本币平台行情
const FTD_TID_ReqUnsubCFETSMarketData = 0x00001132;
//查询债券成交信息
const FTD_TID_ReqQryBondExecReport = 0x0000110D;
//查询债券成交信息响应
const FTD_TID_RspQryBondExecReport = 0x0000110E;
//请求从行情中心订阅行情
const FTD_TID_ReqSubMDfromMC = 0x00001140;
//请求从行情中心退订行情
const FTD_TID_ReqUnSubMDfromMC = 0x00001142;
//请求订阅策略对应RFQ报价
const FTD_TID_ReqSubRFQByClientID = 0x00001150;
//请求退订策略对应RFQ报价
const FTD_TID_ReqUnSubRFQByClientID = 0x00001152;
//请求增加策略
const FTD_TID_ReqInsertRule = 0x00001010;
//请求增加策略响应
const FTD_TID_RspInsertRule = 0x00001011;
//请求修改策略状态
const FTD_TID_ReqUpdateRuleStatus = 0x00001030;
//请求修改策略状态响应
const FTD_TID_RspUpdateRuleStatus = 0x00001031;
//请求更新策略属性
const FTD_TID_ReqUpdateRuleProp = 0x00001040;
//请求更新策略属性响应
const FTD_TID_RspUpdateRuleProp = 0x00001041;
//策略回报
const FTD_TID_RtnRule = 0x00001012;
//策略运行状态变化回报
const FTD_TID_RtnRuleStatus = 0x00001032;
//策略属性变化回报
const FTD_TID_RtnRuleProp = 0x00001044;
//策略指标回报
const FTD_TID_RtnRuleIndicator = 0x00001045;
//深度行情回报
const FTD_TID_RtnDepthMarketData = 0x00006001;
//行情Bar回报
const FTD_TID_RtnMarketDataBar = 0x00006002;
//报价行情回报
const FTD_TID_RtnQuoteMarket = 0x00001103;
//债券市场成交回报
const FTD_TID_RtnBondExecReport = 0x00001110;
//新本币平台深度行情回报
const FTD_TID_RtnCFETSDepthMarketData = 0x00001133;
//报价接收回报
const FTD_TID_RtnCfetsRFQReceive = 0x00001134;
//CME/CBOT深度行情回报
const FTD_TID_RtnCMEDepthMarketData = 0x00001144;
//报单回报
const FTD_TID_RtnRuleOrder = 0x00001102;
//成交回报
const FTD_TID_RtnRuleTrade = 0x00001111;
//持仓变动回报
const FTD_TID_RtnRulePosition = 0x00001100;
//资金变动回报
const FTD_TID_RtnRuleAccount = 0x00001101;
//Api建立连接回报
const FTD_TID_RtnApiConnected = 0x0000110B;
//Api断开连接回报
const FTD_TID_RtnApiDisconnected = 0x0000110C;
//客户端显示消息回报
const FTD_TID_RtnUserMessage = 0x0000110F;
//用户分账号信息回报
const FTD_TID_RtnCustomerAccountInfo = 0x00001114;
//交易成员基本信息回报
const FTD_TID_RtnCfetsTradeMember = 0x00001135;
//心跳通知
const FTD_TID_NotifyHeartBeat = 0x00004500;
//请求更新合约做市状态
const FTD_TID_ReqUpdMakeMarketStatus = 0x00001115;
//请求更新合约做市状态响应
const FTD_TID_RspUpdMakeMarketStatus = 0x00001116;
//合约做市状态回报
const FTD_TID_RtnMakeMarketStatus = 0x00001117;
//请求更新合约做市参数
const FTD_TID_ReqUpdMakeMarketPara = 0x00001118;
//请求更新合约做市参数响应
const FTD_TID_RspUpdMakeMarketPara = 0x00001119;
//合约做市参数回报
const FTD_TID_RtnMakeMarketPara = 0x0000111A;
//请求查询策略限仓额度
const FTD_TID_ReqQryRulePositionLimit = 0x00001120;
//请求查询策略限仓额度响应
const FTD_TID_RspQryRulePositionLimit = 0x00001121;
//请求更改策略限仓额度
const FTD_TID_ReqRulePositionLimitAction = 0x00001122;
//请求更改策略限仓额度响应
const FTD_TID_RspRulePositionLimitAction = 0x00001123;
//请求订阅价差
const FTD_TID_ReqSubPriceSpread = 0x0000112a;
//请求退订价差
const FTD_TID_ReqUnsubPriceSpread = 0x0000112c;
//合约价差回报
const FTD_TID_RtnInsPriceSpread = 0x0000112b;

(function ($) {
    $.extend({
        websocket: function (url, s, protocols) {
            var ws, _s = s;
            var settings = {
                message: function () {
                    console.log("message function is undefined");
                },
                options: {}, events: {}, ver: "1.0", company: "上海尔易信息科技有限公司"
            };
            _reconnect = function (url, protocols) {
                if (protocols) {
                    ws = window['MozWebSocket'] ? new MozWebSocket(url, protocols) : window['WebSocket'] ? new WebSocket(url, protocols) : null;
                } else {
                    ws = window['MozWebSocket'] ? new MozWebSocket(url) : window['WebSocket'] ? new WebSocket(url) : null;
                }
                ws._url = url;
                ws._protocols = protocols;
                $.extend(settings, $.websocketSettings, _s);
                ws.nRequestID = 1;
                if (ws) {
                    $(ws)
                        .bind('open', settings.OnFrontConnected)
                        .bind('close', settings.OnFrontDisconnected)
                        .bind('message', settings.message)
                        .bind('message', function (e) {
                            var m = JSON.stringify(e.originalEvent.data);
                            //eval("m=" + e.originalEvent.data);
                            var h = settings.events[m.Tid];//调用指定的方法
                            if (h) h.call(this, m);
                        });
                    ws._send = ws.send;
                    ws.send = function (type, data) {
                        var m = {Tid: type};//类型
                        m = $.extend(true, m, $.extend(true, {}, settings.options, m));
                        if (data) {
                            delete data["_id"];
                            m['data'] = data;
                        }
                        m['RequestID'] = ws.nRequestID++;
                        return this._send(JSON.stringify(m));
                    };
                    ws.reconnect = function () {
                        setTimeout(function () {
                            _reconnect(ws._url, ws._protocols);
                        }, 1000 * 30);
                        //_reconnect(ws._url, ws._protocols);
                    };
                }
            };
            _reconnect(url, protocols);
            // $(window).unload(function () {
            //     ws.close();
            //     ws = null;
            // });
            $(window).on("unload",function () {
                ws.close();
                ws = null;
            });
            return ws;
        }


        , trade: function (url, s, protocols) {
            var tradeWS = {nRequestID: 1};

            var settings = {
                OnFrontConnected: function () {
                    console.log("OnFrontConnected");
                },
                OnFrontDisconnected: function () {
                    console.log("OnFrontDisconnected");
                },
                OnHeartBeatWarning: function (nTimeLapse) {
                    console.log("OnHeartBeatWarning: " + nTimeLapse);
                },
                OnRspError: function (r) {
                },
                OnRspUserLogin: function (r) {
                },
                OnRspUserLogout: function (r) {
                },
                OnRtnDepthMarketData: function (r) {
                },
                OnRspSubMarketData: function (r) {
                },
                OnRspUnSubMarketData: function (r) {
                },
                OnRtnRule: function (r) {
                },
                OnRtnRuleStatus: function (r) {
                },
                OnRtnRuleProp: function (r) {
                },
                OnRtnRuleIndicator: function (r) {
                },

                message: function (msg) {
                    try {
                        if (event.data instanceof Blob) {
                            var reader = new FileReader();
                            reader.onloadend = function () {
                                console.log(reader.result);
                            };
                            reader.readAsText(event.data, "gbk");//utf-8
                        } else {
                            eval("r=" + event.data);
                            switch (r.Tid) {
                                case FTD_TID_RtnDepthMarketData: {
                                    tradeWS.OnRtnDepthMarketData(r);
                                    break;
                                }
                                case FTD_TID_RspUserLogin: {
                                    tradeWS.OnRspUserLogin(r);
                                    break;
                                }
                                // case FTD_TID_RspError: {
                                //     tradeWS.OnRspError(r);
                                //     break;
                                // }
                                case FTD_TID_RtnRule: {//策略回报
                                    tradeWS.OnRtnRule(r);
                                    break;
                                }
                                case FTD_TID_RtnRuleStatus: {//策略运行状态变化回报
                                    tradeWS.OnRtnRuleStatus(r);
                                    break;
                                }
                                case FTD_TID_RtnRuleProp: {//策略属性变化回报
                                    tradeWS.OnRtnRuleProp(r);
                                    break;
                                }
                                case FTD_TID_RtnRuleIndicator: {//策略指标回报
                                    tradeWS.OnRtnRuleIndicator(r);
                                    break;
                                }
                                case FTD_TID_RspUserLogout: {
                                    tradeWS.OnRspUserLogout(r);
                                    break;
                                }
                                case FTD_TID_RspSubMarketData: {
                                    tradeWS.OnRspSubMarketData(r);
                                    break;
                                }
                                case FTD_TID_RspUnSubMarketData: {
                                    tradeWS.OnRspUnSubMarketData(r);
                                    break;
                                }
                                case FTD_TID_IntlRtnDepthMarketData: {
                                    tradeWS.OnRspError(r);
                                    break;
                                }
                                default:
                                    OnHeartBeatWarning(r);
                            }

                            console.log("log: " + event.data);
                        }

                    } catch (e) {
                        console.log(e.message + " : " + event.data);
                    }
                },
                options: {},
                events: {}
            };
            $.extend(settings, $.websocketSettings, s, tradeWS);
            tradeWS.ws = $.websocket(url, settings, protocols);

            tradeWS.OnFrontConnected = settings.OnFrontConnected;
            tradeWS.OnFrontDisconnected = settings.OnFrontDisconnected;
            tradeWS.OnHeartBeatWarning = settings.OnHeartBeatWarning;
            tradeWS.OnRspError = settings.OnRspError;
            tradeWS.OnRspUserLogin = settings.OnRspUserLogin;
            tradeWS.OnRspUserLogout = settings.OnRspUserLogout;
            tradeWS.OnRtnDepthMarketData = settings.OnRtnDepthMarketData;
            tradeWS.OnRspSubMarketData = settings.OnRspSubMarketData;
            tradeWS.OnRspUnSubMarketData = settings.OnRspUnSubMarketData;
            tradeWS.OnRtnRule = settings.OnRtnRule;
            tradeWS.OnRtnRuleStatus = settings.OnRtnRuleStatus;
            tradeWS.OnRtnRuleProp = settings.OnRtnRuleProp;
            tradeWS.OnRtnRuleIndicator = settings.OnRtnRuleIndicator;

            //启动或停止策略发送到后台
            tradeWS.ReqOptionStg = function(optype, ruleid){
              this.ws.send(FTD_TID_ReqOptionStg, {
                  "optype": optype,
                  "stgid": ruleid
              })
            };

            //策略参数发送到websocket
            tradeWS.ReqStgPara = function(ruleid, key, value, desc){
                this.ws.send(FTD_TID_ReqStgPara, {
                    "stgid": ruleid,
                    "stgname": key,
                    "stgvalue": value,
                    "stgdesc": encodeURI(desc) //中文乱码,用url编码,python在后台url解码
                })
            }

            tradeWS.ReqUserLogin = function (u, p) {
                this.ws.send(FTD_TID_ReqUserLogin, {
                    'CustomerID': u,
                    'Password': p,
                    'ProductInfo': '',
                    'InterfaceProductInfo': 'websocket'
                });
            };
            tradeWS.SubscribeMarketData = function (ppInstrumentIDs) {
                if (ppInstrumentIDs.length > 0)
                    this.ws.send(FTD_TID_ReqSubMarketData, {'InstrumentID': ppInstrumentIDs, "ExchangeID": "CFFEX"});
                else
                    alert("请选择要订阅行情的合约!");
            };
            tradeWS.UnSubscribeMarketData = function (ppInstrumentIDs) {
                if (ppInstrumentIDs.length > 0)
                    this.ws.send(FTD_TID_ReqUnSubMarketData, {'InstrumentIDs': ppInstrumentIDs});
                else
                    alert("请选择要取消订阅行情的合约!");
            };
            return tradeWS;
        }
    });

})(jQuery);


                        
            
## 后端代码(STCHftData.py)
# encoding: UTF-8

from time import sleep

from hft_api import HftApi

import os
import json
import threading
import copy
import multiprocessing
from websocket_server import WebsocketServer

global signal

from enum import Enum
from process_manager import process_manager
import pandas as pd
from sqlalchemy import create_engine
import urllib.parse


class run_status_enum(Enum):
    运行中 = 1
    已结束 = 2  # 回测模拟
    已分析 = 3  # 回测模拟
    未运行 = 4
    待运行 = 5
    待停止 = 6
    错误 = 7  # 回测模拟


# signal = threading.Event()
def print_dict(d):
    """按照键值打印一个字典"""
    for key, value in d.items():
        print(key + ':' + str(value))


def simple_log(func):
    """简单装饰器用于输出函数名"""

    def wrapper(*args, **kw):
        print(str(func.__name__))
        return func(*args, **kw)

    return wrapper


class TestMdApi(HftApi):
    """测试用实例"""

    def __init__(self, Queue1):
        """Constructor"""
        super(TestMdApi, self).__init__()
        # 1. 创建1个队列
        self.tid_Queue = Queue1

    @simple_log
    def onFrontConnected(self):
        """服务器连接"""
        signal = 1
        pass

    @simple_log
    def onFrontDisconnected(self, n):
        """服务器断开"""
        print(n)
        signal = 0

    @simple_log
    def onHeartBeatWarning(self, n):
        """心跳报警"""
        print(n)

    @simple_log
    def onRspError(self, error, n, last):
        """错误"""
        print_dict(error)

    @simple_log
    def onRspUserLogin(self, data, error, data2, n, last):
        """登陆回报"""
        print_dict(data)
        print_dict(error)

    @simple_log
    def onRspUserLogout(self, data, error, n, last):
        """登出回报"""
        print_dict(data)
        print_dict(error)

    def onRspUnSubMarketData(self, data, error, n, last):
        """退订合约回报"""
        print_dict(data)
        print_dict(error)

    def onRtnDepthMarketData(self, data):
        """行情推送"""
        print_dict(data)
        # print('子进程1进程>>', os.getpid())
        package = {'Tid': 0x00002008, 'data': data}
        self.save_as_json(package, "onRtnDepthMarketData")

    # ----------------------------------------------------------------------
    def onRtnForQuoteRsp(self, data):
        """行情推送"""
        print_dict(data)

    def onRspUpdateRuleStatus(self, data, error, n, last):
        """更改C++ 策略更新状态响应"""
        # print_dict(error)
        package = {'Tid': 0x00001031, 'data': data}
        self.save_as_json(package)

    def onRspUpdateRuleProp(self, data, error, n, last):
        # print_dict(error)
        """更改C++ 策略更新属性响应"""
        package = {'Tid': 0x00001041, 'data': data}
        self.save_as_json(package, "onRspUpdateRuleProp")

    def onRtnRuleIndicator(self, data):
        """策略指标回报"""
        package = {'Tid': 0x00001045, 'data': data}
        self.save_as_json(package, "onRtnRuleIndicator")
        # save ruleid+key

    def onRtnRuleProp(self, data):
        """策略属性变化回报"""
        package = {'Tid': 0x00001044, 'data': data}
        self.save_as_json(package, "onRtnRuleProp")
        # save

    def onRtnRuleStatus(self, data):
        """策略状态变化回报"""
        package = {'Tid': 0x00001032, 'data': data}
        self.save_as_json(package)

    @simple_log
    def onRtnRule(self, data):
        """策略回报"""
        package = {'Tid': 0x00001012, 'data': data}
        self.save_as_json(package, "onRtnRule")

    """
    主动API接口封装
    """

    # 在C++环境中创建MdApi对象,传入参数是希望用来保存.con文件的地址
    # @param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录
    # @return 创建出的UserApi
    # modify for udp marketdata
    def CreateFtdcMdApi(self, path):
        if os.path.exists(path) and path[-1] == '\\':
            type = ''
            self.createUserApi(path, type)
        else:
            print('con file path error')

    # 删除接口对象本身
    # @remark 不再使用本接口对象时,调用该函数删除接口对象
    def Release(self):
        self.release()

    # 初始化
    # @remark 初始化运行环境,只有调用后,接口才开始工作
    def Init(self):
        self.init()

    # 等待接口线程结束运行
    # @return 线程退出代码
    def Join(self):
        self.join()

    # 退出
    def Exit(self):
        self.exit()

    # 获取当前交易日
    # @retrun 获取到的交易日
    # @remark 只有登录成功后,才能得到正确的交易日
    def GetTradingDay(self):
        trade_date = self.getTradingDay()
        return trade_date

    # 注册前置机网络地址
    # @param pszFrontAddress:前置机网络地址。
    # @remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:17001”。
    # @remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”17001”代表服务器端口号。
    def RegisterFront(self, ip_address):
        self.registerFront(ip_address)

    # 用户登录请求
    def ReqUserLogin(self):
        # signal.wait()
        # 登陆
        print("ready to login")
        loginReq = {}  # 创建一个空字典
        loginReq['CustomerID'] = '1001'  # 参数作为字典键值的方式传入
        loginReq['Password'] = '123456'  # 键名和C++中的结构体成员名对应
        loginReq['MacAddress'] = '00-50-56-C0-00-01'
        loginReq['SubInstrumentMethod'] = '0'
        loginReq['IsRule'] = 0
        self.reqUserLogin(loginReq, 1)

    # 登出请求
    def ReqUserLogout(self):
        self.reqUserLogout()

        # 订阅行情。
        # @param ppInstrumentID 合约ID
        # @param nCount 要订阅/退订行情的合约个数

    def SubscribeMarketData(self, msg):
        subReq = {}
        subReq['InstrumentID'] = msg['data']['InstrumentID']
        subReq['ExchangeID'] = msg['data']['ExchangeID']
        self.reqSubMarketData(subReq, 2)

        # self.subscribeMarketData(ppInstrumentID)

    # 退订行情。
    # @param ppInstrumentID 合约ID
    # @param nCount 要订阅/退订行情的合约个数
    def UnSubscribeMarketData(self, ppInstrumentID):
        self.unSubscribeMarketData(ppInstrumentID)

    # 请求修改策略状态
    def ReqUpdateRuleStatus(self, req):
        self.reqUpdateRuleStatus(req, 3)

    # 请求修改策略状态
    def ReqUpdateRuleProp(self, req):
        self.reqUpdateRuleProp(req, 4)

    # 业务流程处理
    def subs(self):
        self.CreateFtdcMdApi('mdcon\\')
        self.RegisterFront("tcp://127.0.0.1:32201")
        self.Init()
        sleep(1)
        self.ReqUserLogin()
        sleep(1)

        # 请求修改策略状态_启动策略
        ruleReq = {}  # 创建一个空字典
        ruleReq['RuleID'] = 1  # 策略代码
        ruleReq['RuleOperType'] = '0'  # 策略运行状态类型设定
        self.ReqUpdateRuleStatus(ruleReq)

        # 请求更新策略属性
        # for i in range(0,1000):
        ruleReq2 = {}  # 创建一个空字典
        ruleReq2['RuleID'] = 1  # 策略代码
        ruleReq2['PropKey'] = 'OrderPrice'  # 策略属性键
        ruleReq2['PropValue'] = '99.5'  # 策略属性值
        ruleReq2['PropType'] = '1'  # 策略属性值类型
        ruleReq2['PropValueItems'] = '1'  # 策略属性值选项
        ruleReq2['Description'] = '报单价格'.encode('gbk')  # 描述
        self.ReqUpdateRuleProp(ruleReq2)

        # # 请求修改策略状态_关闭策略
        # ruleReq['RuleID'] = 1  # 策略代码
        # ruleReq['RuleOperType'] = '1'  # 策略运行状态类型设定
        # self.ReqUpdateRuleStatus(ruleReq)

    # 数据转换
    def save_as_json(self, package, func=""):
        json_package = json.dumps(package)
        # self.tid_Queue.put(json_package)
        self.tid_Queue.put(package)
        # if self.tid_Queue.qsize() % 10 == 0:
            # print('打包 现在队列里面有包数:', self.tid_Queue.qsize())


#####################################
class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args:  # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False


# 自定义常量类,类名要大写,不可修改。python中只规定常量大写,建议不可修改,若想不可修改,自定义类。
# 策略回报
FTD_Tid_RtnRule = 0x00001012;
# 策略运行状态变化回报
FTD_Tid_RtnRuleStatus = 0x00001032;
# 策略属性变化回报
FTD_Tid_RtnRuleProp = 0x00001044;
# 策略指标回报
FTD_Tid_RtnRuleIndicator = 0x00001045;

global client_list
client_list = []
global total_dict


class SocketEnv():
    def __init__(self, queue1):
        """Constructor"""
        super(SocketEnv, self).__init__()
        self.total_dict = {}  # 全量数据
        # tid_Queue          增量数据队列
        self.tid_Queue = queue1

    r = 'r是什么,r是传递的data,case是r.Tid'
    v = 'ten'  # 若按照此写法,v=r.Tid

    def caseswitch(self, req_msg):
        for case in switch(req_msg["Tid"]):
            print('前端请求HFT数据:', type(req_msg), req_msg)
            # 带on的是回报,不带on的是请求,关注请求即可
            if case(FTD_Tid_RtnRule):
                # self.api.onRtnDepthMarketData(req_msg)
                break
            if case(FTD_Tid_RtnRuleStatus):
                # self.api.onRspUserLogin(req_msg)
                break
            if case(FTD_Tid_RtnRuleProp):
                # self.api.OnRspError(req_msg)
                break
            if case(FTD_Tid_RtnRuleIndicator):
                # self.api.OnRspUserLogout(req_msg)
                break
            if case():  # default, could also just omit condition or 'if True'
                print('switch case default!')

    def startWebsocketServer(self):

        def login(msg):
            # switch case
            if msg["Tid"] == 8201:
                api.SubscribeMarketData(msg)
                print("行情定阅成功")
            else:
                data = msg["data"]
                try:
                    if data['CustomerID'] == '1001' and data['Password'] == '123456':
                        return True
                    else:
                        return False
                except Exception as e:
                    print(e)
                    return False

        def onmessage(client, server, msg):
            jsonObject = json.loads(msg)
            print("前端传来了:", jsonObject)
            if jsonObject["data"].get("stgdesc"):
                stgdesc = jsonObject['data']
                data = urllib.parse.quote(stgdesc)
                print(data)

            if jsonObject["data"].get("optype"):
                try:
                    optype = jsonObject['data']["optype"]
                    stgid = jsonObject['data']['stgid']
                    if optype == "end":
                        self.init_run(6, stgid)
                        print("待停止发送成功!!")
                    elif optype == "start":
                        self.init_run(5, stgid)
                        print("待启动发送成功!!")
                except Exception as e:
                    print(e)
            islogin = login(jsonObject)
            if client in client_list:
                pass
                # 请求switchcase方法
            else:
                if islogin:
                    client_list.append(client)
                    # 登录成功,推全量数据给用户
                    print('登录成功,推全量数据给用户')
                    print(self.total_dict)
                    for key in self.total_dict:
                        data = self.total_dict[key]
                        server.send_message_to_all(json.dumps(data))
                    return True
                else:
                    pass
                    # 登录失败
                # // server.send_message(client, json.dumps({"Tid": 1111, "data": {"msg": "登陆失败"}}))

        def sendDataToAllClient():
            while True:
                jsonData = self.tid_Queue.get()
                if jsonData == None:
                    sleep(0.1)
                if jsonData["Tid"] == FTD_Tid_RtnRule:  # 策略
                    self.total_dict[jsonData['data']['RuleID']] = jsonData
                elif jsonData['Tid'] == FTD_Tid_RtnRuleStatus:  # 状态4146
                    self.total_dict[str(jsonData['data']['RuleID']) + '_' + 'status'] = jsonData
                elif jsonData["Tid"] == FTD_Tid_RtnRuleProp:  # 参数4164
                    self.total_dict[str(jsonData['data']['RuleID']) + '_' + jsonData['data']['PropValue']] = jsonData
                elif jsonData["Tid"] == FTD_Tid_RtnRuleIndicator:  # 指标4165
                    self.total_dict[str(jsonData['data']['RuleID']) + '_' + jsonData['data']['IndicatorKey']] = jsonData

                client_list_copy = copy.copy(client_list)
                for client in client_list_copy:
                    sleep(0.1)
                    server.send_message(client, json.dumps(jsonData))

        # 这是服务端,所以需要监听的是本机的ip,通过ipconfig拿到,
        # 同时在linux上的客户端也需要监听这个ip和端口。
        # server = WebsocketServer(9000, host='172.16.78.228')
        # server = WebsocketServer(9000, host='172.19.190.191')
        server = WebsocketServer(9000, host='127.0.0.1')
        server.set_fn_message_received(onmessage)
        t1 = threading.Thread(target=sendDataToAllClient)
        t1.start()
        server.run_forever()
        server.server_close()

    def init_run(self, run_status, stg_id):
        '''
        1运行中  2已结束  3已分析  4未运行  5待运行   6待停止  7错误
        '''

        # 数据库
        user = 'root'
        password = 'XCL29hao'
        ip_address = '111.231.16.33'
        port = 3306
        db_name = 'strategy'
        # 表名
        self.db_approval = 't_paperapproval'
        self.db_run = 't_paperrun'

        # 配置文件
        self.ini_host = '127.0.0.1'
        self.ini_port = 50000
        self.ini_api_mode = 'HFT_Address_IP'
        self.ini_api_host = '127.0.0.1'
        self.ini_api_port = '32201'

        # python exe文件, 保存路径
        self.python_path = 'D:\\program\\Anaconda3'
        self.target_path = 'D:'

        # 遍历周期
        self.sleep_period = 10
        # 数据库连接
        self.engine_str = f'mysql+mysqlconnector://{user}:{password}@{ip_address}:{port}/{db_name}?charset=utf8'
        self.engine = create_engine(self.engine_str)

        try:
            # 进程管理
            process_main = process_manager()

            print('运行一次进程启动...')
            # 进程管理器
            process_main.get_current_process()

            # 读取需要启停的进程
            content = f'select * from {self.db_run} where StgID = {stg_id}'
            sql_df = pd.read_sql_query(content, self.engine)

            if len(sql_df) == 0:
                return 0

            # 类型转换
            run_status = int(run_status)
            stg_id = str(stg_id)
            path = sql_df['RunPath'].tolist()[0]

            # 启动进程
            if run_status == run_status_enum.待运行.value:
                # 运行进程
                flag = process_main.start_process(path)

                if flag:
                    # 更新run表
                    try:
                        content = f'update {self.db_run} set RunStatus = \
                        {run_status_enum.运行中.value}, StartTime = \
                        "{datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")}" \
                        where StgID = {stg_id}'
                        pd.read_sql_query(content, self.engine)
                    except Exception as e:
                        pass
            # 终止进程
            elif run_status == run_status_enum.待停止.value:
                # 终止进程
                flag = process_main.end_process(stg_id)

                if flag:
                    # 更新run表
                    try:
                        content = f'update {self.db_run} set RunStatus = \
                        {run_status_enum.未运行.value}, EndTime = \
                        "{datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")}" \
                        where StgID = {stg_id}'
                        pd.read_sql_query(content, self.engine)
                    except Exception as e:
                        pass
        except Exception as e:
            print(e)


"""
消耗多进程队列的func
"""


def main():
    """
    @ERYI.tcy
    """
    # 初始化
    # print('父进程>>', os.getpid())
    # 创建一个实时更新队列-存储实时数据
    tid_Queue = multiprocessing.Queue()

    p1 = multiprocessing.Process(target=TestMdApi, args=(tid_Queue,))
    global api
    api = TestMdApi(tid_Queue)
    api.subs()
    p1.start()

    # p1.daemon = True
    p2 = multiprocessing.Process(target=SocketEnv, args=(tid_Queue,))
    p2.start()

    socket_env = SocketEnv(tid_Queue)
    #     # api的业务操作测试 从hft取数据比如请求订阅行情、收策略回报等
    socket_env.startWebsocketServer()

    i = 1
    while True:
        if i == 0:
            break
    api.Exit()

    print("父进程结束")


if __name__ == '__main__':
    main()

遇到一些问题

'''
websocket服务端
	
	如果部署在服务器上,则监听的是内网ip(阿里云:命令是ifconfig, windowserver:命令是ipconfig), 而客户端连接的是公网ip(服务器外网访问的ip) 
	如果部署在本地,则监听的是本机的ip, 客户端连接的是本机的ip,通过ipconfig查看本机(ipv4地址),不然的话有可能会抱胸:在其上下文,该请求地址无效,主要就是ip+端口错误导致的。
	
	
'''
posted @ 2020-06-30 22:59  Micheal_L  阅读(1113)  评论(0编辑  收藏  举报