django+websocket

websocket知识点

安装:
pip install websocket-server

注意事项:
当运行了 run_forever 方法后,当前线程就阻塞了。
如果在之后要调用 send_message_to_all方法,利用多线程。

html页面

base.html

{% load staticfiles %}

<!-- <!DOCTYPE html> -->
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    {% block head_link %}{% endblock %}
    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">

    <link rel="stylesheet" href="{% static '/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static '/bower_components/font-awesome/css/font-awesome.min.css' %}">
    <link rel="stylesheet" href="{% static  '/bower_components/Ionicons/css/ionicons.min.css' %}">
    <!-- <link rel="stylesheet" href="{% static  '/plugins/bootstrap-datatable/bootstrap-table.css' %}"> -->
    <link rel="stylesheet" href="{% static '/bootstrap_table/bootstrap-table/dist/bootstrap-table.min.css' %}">
    <link rel="stylesheet" href="{% static  '/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static '/plugins/iCheck/all.css' %}">
    <link rel="stylesheet" href="{% static '/plugins/bootstrapValidator/bootstrapValidator.min.css' %}">
    <link rel="stylesheet" href="{% static '/plugins/bootstrap-dialog/bootstrap-dialog.min.css' %}">
    <!-- <link rel="stylesheet" href="{% static '/dist/css/AdminLTE.min.css' %}"> -->
    <!-- <link rel="stylesheet" href="{% static '/plugins/timepicker/bootstrap-timepicker.css' %}"> -->
    <!-- <link rel="stylesheet" href="{% static '/dist/css/skins/skin-blue.min.css' %}"> -->
    <link rel="stylesheet" href="{% static '/public.css' %}">
    <link rel="stylesheet" href="{% static '/datetimepicker/bootstrap-datetimepicker.min.css' %}">

    <!-- 子模板的样式表应放在父模板的样式表之后,只有这样才可以在子模板中重定义父模板中的某些样式 -->
    {% block styles %}{% endblock %}
    <style>
        .btn-group-xs > .btn, .btn-xs {
            padding: 0px 6px;
            font-size: 11px;
            line-height: 1.5;
            border-radius: 3px;
        }

        .table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {
            padding: 4px;
            line-height: 1.2;
            vertical-align: top;
            border-top: 1px solid #ddd;
        }

        .skin-blue .main-header .logo {
            background-color: #2b2b2b;
            color: #fff;
            border-bottom: 0 solid transparent;
        }


        .skin-blue .wrapper, .skin-blue .main-sidebar, .skin-blue .left-side {
            background-color: #141414;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        .main-footer {
            background: #000;
            padding: 15px;
            color: #f39c12;
            border-top: 1px solid #000;
        }


        th {
            text-align: center;
        }

        td {
            text-align: center;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        label {
            width: 100px;
            margin-left: 5%;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        input, select {
            width: 160px;
            height: 24px;
            background: #0F0F0F;
            border: 1px solid #3C3C3C;
            border-radius: 1px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        /* 模态框下的input */
        .opts {
            background-color: white;
            width: 200px;
        }

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

        /* input-file放在同一行 */
        input[type=file] {
            display: inline-block;
            /* cursor: pointer; */
            border: none;
            width: auto;
        }

        button {
            border: none;
        }

        .btn-query {
            width: 87px;
            height: 26px;
            background: #3C3C3C;
            border-radius: 3px;
        }

        .conf {
            border: 0; /*去掉未选中状态边框*/
            outline: none; /*去掉选中状态边框*/
            background-color: rgba(0, 0, 0, 0); /*透明背景*/
        }

        .bootstrap-table {
            border-style: solid;
            border-width: 3px;
            border: 1px solid rgba(0, 0, 0, .15);
        }

        .pagination-info {
            display: none
        }

        .page-list {
            display: none
        }

        .modal-dialog {
            width: 450px;
        }

        .modal-body {
            /* background-color: #282923; */
            padding: 10px 30px;
            height: auto;
        }

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

        stg_check {
            padding: 10px;
        }

        .row {
            margin-top: 10px;
        }

        /* 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;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

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

        /* 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;
        }

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

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

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

        }

        .upstrategy {
            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;
        }

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

        /* bootstraptable左侧边框 */
        .table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > th {
            border: 1px solid #1E1E1E;
            background: #1E1E1E;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td {
            border: 1px solid #1E1E1E;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
            color: #DCDCDC;
        }
        #stcriskinfoTable > thead > tr > td, #stcriskinfoTable > tbody > tr > td {
            border: 1px solid #f5f5f5;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
            color: #939393;
        }

        tr.activetable, input.activetable {
            background-color: white;
            width: 100px;
            height: 30px;
            margin: 1px;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        /*确认页面的table,去掉边框线*/
        tr.confirm_table, input.confirm_table {
            background-color: white;
            width: 100px;
            height: 30px;
            margin: 1px;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
            border-width: 0;
            text-align: center;
        }


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

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


        /* integrated css */
        .tab-content {
            margin-left: 10px;
        }

        .div-query {
            float: left;
            margin-top: 15px;
            margin-left: 10px;
            margin-bottom: 15px;
            color: #ffffff;
        }

        /* 新增按钮格式 */
        .btn-add {
            float: left;
            width: 100px;
            height: 26px;
            /* background: inherit; */
            background-color: rgba(255, 204, 153, 1);
            border-radius: 5px;
            /* box-sizing: border-box;
            border-width: 1px;
            border-style: solid;
            border-color: rgba(121, 121, 121, 1);
            -moz-box-shadow: none;
            -webkit-box-shadow: none;
            box-shadow: none; */
            color: #2B2B2B;
        }

        /* 查询按钮格式 */
        .btn-query {
            width: 80px;
            height: 26px;
            background: #3C3C3C;
            border-radius: 5px;
        }

        /* 按钮通用属性 */
        .btn-stc {
            border-radius: 5px;
            text-align: center;
            display: table-cell;
            vertical-align: middle;
            cursor: pointer;
        }

        /* 提交按钮 */
        .btn-confirm {
            width: 100px;
            height: 26px;
            background: red;
            color: #ffffff;
        }

        /* 取消按钮 */
        .btn-cancel {
            width: 60px;
            height: 26px;
            background: #3C3C3C;
            color: #ffffff;
        }

        /* 查询面板label格式 */
        .lbl-query {
            margin-left: 30px;
            float: left;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
            color: #cdcdcd;
        }

        /* 订单查询label面板 */
        .order-query {
            margin-left: 15px;
            float: left;
            font-size: 12px;
            font-family: NotoSansCJKsc-Regular, sans-serif;
            color: #cdcdcd;
        }


        /* 查询面板输入框格式 */
        .input-query {
            width: 120px;
        }

        /*环境选择input框*/
        .envir-input-query {
            width: 75px;
        }

        /*清算速度input框*/
        .tid-input-query {
            width: 70px;
        }
        /*方向input框*/
        .direction-input-query {
            width: 45px;
        }
        /*策略ID input框*/
        .id-input-query {
            width: 50px;
        }
        /*债券代码 input 框*/
        .instrid-input-query {
            width: 60px;
        }

        /*历史持仓 日期 input 框*/
        .date-input-query {
            width: 70px;
        }

        .table-stc {
            table-layout: fixed;
            word-break: break-all;
            word-wrap: break-all;
            font-size: 12px;
            width: 100%;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        section {
            margin: 0px 5px 0px 10px;
        }

        /* 操作成功样式 */
        .operat-success {
            margin-top:25px;
            margin-left:5px;
            font-size: 18px;
            text-align: center;
        }

        /* 输入框校验失败文字展示 */
        .input-validation {
            color: red;
            margin-left: 102px;
        }

        /* 人工录入错误提示输入框*/
        .error_input {
            color: red;
            margin-left: 112px;
        }

        /* 策略参数输入框错误提示*/
        .input-stgpara {
            color: red;
            margin-left: 40px;
        }

        /*滚动条样式*/
        div::-webkit-scrollbar {
            width: 4px;
            display: block;
        }

        /*滚动条样式*/
        div::-webkit-scrollbar-thumb {
            border-radius: 20px;
            background: #777;
        }


        /*滚动条样式*/
        div::-webkit-scrollbar-button {
            display: none;
        }

        /*滚动条样式*/
        div::-webkit-scrollbar-track {
            background: #2b2b2b;
        }

        /* 统一修改页面宽高、背景色和字体 */
        body {
            background: #000;
            height: 100%;
            width: 100%;
            font-family: NotoSansCJKsc-Regular, sans-serif;
        }

        /*隐藏浏览器滚动条,但是不影响滑动*/
        body::-webkit-scrollbar {
            width: 0px;
        }

        /*风控信息隐藏浏览器滚动条,但是不影响滑动*/
        #stcriskinfo_id::-webkit-scrollbar {
            width: 0px;
        }

        /*右侧页码样式*/
        .pagination > li > a, .pagination > li > span {
            position: relative;
            float: left;
            padding: 6px 12px;
            margin-left: -1px;
            line-height: 1.42857143;
            color: #ddd;
            text-decoration: none;
            background-color: rgba(0, 0, 0, .0001);
            border: 1px solid rgba(255, 255, 255, .15);
        }


    </style>

</head>

<body class="hold-transition skin-blue sidebar-mini">

<div class="wrapper">

    <!-- Left side column. contains the logo and sidebar -->
    <!-- <aside class="main-sidebar"></aside> -->
    <!-- Content Wrapper. Contains page content -->
    <div class="content-wrapper">
        {% block content %}
        {% endblock %}
    </div>
    <!-- /.content-wrapper -->
    <!-- Main Footer -->
    <footer class="main-footer">
        <!-- To the right -->
        <div class="pull-right hidden-xs">
        </div>
    </footer>
</div>


<!-- Jquery -->
<script src="{% static '/bower_components/jquery/dist/jquery.min.js' %}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{% static '/bower_components/bootstrap/dist/js/bootstrap.min.js' %}"></script>
<!-- DataTables -->
<script src="{% static '/bower_components/datatables.net/js/jquery.dataTables.min.js' %}"></script>
<script src="{% static '/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js' %}"></script>
<script src="{% static '/plugins/jquery-form/jquery.form.min.js' %}"></script>
<script src="{% static '/plugins/iCheck/icheck.min.js' %}"></script>
<!-- 验证 -->
<script src="{% static '/plugins/bootstrapValidator/bootstrapValidator.min.js' %}"></script>
<script src="{% static '/plugins/jquery-cookie/jquery.cookie.min.js' %}"></script>
<!-- Echart -->
<script src="{% static '/plugins/echart/echarts.min.js' %}"></script>
<script src="{% static '/plugins/bootstrap-dialog/bootstrap-dialog.min.js' %}"></script>
<!-- Theme style -->
<!-- <script src="{% static '/dist/js/adminlte.min.js' %}"></script> -->
<script src="{% static '/public.js' %}"></script>
<script src="{% static '/datetimepicker/bootstrap-datetimepicker.js' %}"></script>
<script src="{% static '/plugins/timepicker/bootstrap-timepicker.js' %}"></script>
<script src="{% static '/datetimepicker/jszip.min.js' %}"></script>

<script>

</script>
<!--bootstrap-->
<!--bootstrap-table-->
<script src="{% static '/bootstrap_table/bootstrap-table/dist/bootstrap-table.min.js' %}"></script>
<!--bootstrap-table-lanuage-->
<!--bootstrap-table-export-->
<script src="{% static '/bootstrap_table/bootstrap-table-export.js' %}"></script>
<!--在客户端保存生成的导出文件-->
<script src="{% static '/bootstrap_table/FileSaver.min.js' %}"></script>
<!--以XLSX(Excel 2007+ XML格式)格式导出表(SheetJS)-->
<script src="{% static '/bootstrap_table/xlsx.core.min.js' %}"></script>
<!--无论期望的格式如何,最后都包含 tableexport.jquery.plugin(不是tableexport)-->
<script src="{% static '/bootstrap_table/tableExport.js' %}"></script>

<!--导入websocket和jquery--->
{#<script src="{% static 'bootstrap_table/jquery-1.12.4.min.js' %}"></script>#}
{#        <script src="{% static 'model.js' %}"></script>#}
<script src="{% static 'bootstrap_table/websocket.js' %}"></script>
<script src="{% static 'bootstrap_table/model.js' %}"></script>

<!--导入配置文件-->
<script src="{% static 'config.js' %}"></script>


{% block scripts %}
{% endblock %}

</body>
</html>

paper_monitor

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

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

{% block styles %}
    <style>


        {#表头样式#}
        .thead-light {
            width: auto;
            background-color: #ddd;
        }


        .pagination-info {
            display: none
        }

        .page-list {
            display: none
        }

        #sse {
            color: #36a9ce;
        }

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

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

        #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: 75px;
        }

        {#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 {
            margin-bottom: 0 !important;
            color: #A0A0A0;
        }

        .alterpara {
            background-color: white;
        }


    </style>
{% endblock %}

{% block content %}
    <!--策略修改模态框-->
    <div class="modal fade" id="editstg" data-backdrop="static" tabindex="-1" role="dialog"
         aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title">修改策略参数</h4>
                </div>
                <div class="modal-body">
                    <form>
                        <div style="margin-top:3%;display: none">
                            <label>参数ID</label>
                            <input class="opts" type="text" id="paraid">
                        </div>
                        <div style="margin-top:3%">
                            <label>参数名</label>
                            <input class="opts" type="text" id="paraname" disabled style="background-color: #919191">
                        </div>
                        <div style="margin-top:3%">
                            <label>参数值</label>
                            <input class="opts" type="text" id="paravalue">
                            <div id="para_spaninfo" style="color: red;margin-left: 112px"></div>
                        </div>
                        <div style="margin-top:3%">
                            <label>描述</label>
                            <input class="opts" type="text" id="paradesc">
                        </div>
                        <hr>
                        <div style="height: 20px; display: block">
                            <div style="padding-left:120px; float: left;">
                            <span class="btn-cancel btn-stc"
                                  onclick="quit__()">取消</span>
                            </div>
                            <div style="padding-left:5px;float: left;">
                            <span class="btn-confirm btn-stc"
                                  onclick="sub()">提交</span>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <!--修改成功模态框-->
    <div class="modal fade" data-backdrop="static" id="oper_success">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title" id="title_success">修改参数</h4>
                </div>
                <div class="modal-body">
                    <div>
                        <p id="msg_success" class="operat-success">
                            策略修改成功!</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!--人工录入模态框-->
    <div class="modal fade" id="input_" data-backdrop="static" tabindex="-1" role="dialog"
         aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title">人工录入</h4>
                </div>
                <div class="modal-body">
                    <form>
                        <div style="display: none">
                            <input id="manual-ruleid">
                            <input id="manual-rulename">
                        </div>
                        <div style="margin-top:3%; display: block">
                            <label>债券代码*</label>
                            <input class="opts" id="bondcode" name="bondcode" type="text"
                                   placeholder="债券代码">
                            <div id="bodecode_spaninfo" class="error_input"></div>
                        </div>
                        <div style="margin-top:3%">
                            <label>方向*</label>
                            <select class="opts" id="direction" name="direction">
                                <option selected value="">
                                </option>
                                <option value="0">
                                    Bid
                                </option>
                                <option value="1">
                                    Ofr
                                </option>
                            </select>
                            <div id="direction_spaninfo" class="error_input"></div>
                        </div>
                        <div style="margin-top:3%">
                            <label>清算速度*</label>
                            <select class="opts" id="speedliqui" name="speedliqui">
                                <option value="1">
                                    T+0
                                </option>
                                <option selected value="2">
                                    T+1
                                </option>
                            </select>
                            <div id="speedliqui_spaninfo" class="error_input"></div>
                        </div>
                        <div style="margin-top:3%; display: block">
                            <label>成交价(%)*</label>
                            <input class="opts" id="tranc" name="tranc" type="text"
                                   placeholder="成交价">
                            <div id="tranc_spaninfo" class="error_input"></div>
                        </div>
                        <div style="margin-top:3%; display: block">
                            <label>净价(元)*</label>
                            <input class="opts" id="netprice" name="netprice" type="text"
                                   placeholder="净价">
                            <div id="netprice_spaninfo" class="error_input"></div>
                        </div>
                        <div style="margin-top:3%; display: block">
                            <label>成交量(%)*</label>
                            <input class="opts" id="vol" name="vol" type="text"
                                   placeholder="成交量">
                            <div id="vol_spaninfo" class="error_input"></div>
                        </div>
                        <hr>
                        <div style="height: 20px; display: block">
                            <div style="padding-left:120px; float: left;">
                            <span class="btn-cancel btn-stc"
                                  onclick="quit__()">取消</span>
                            </div>
                            <div style="padding-left:5px;float: left;">
                            <span class="btn-confirm btn-stc"
                                  onclick="input_sub()">提交</span>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <!--人工录入确认模态框-->
    <div class="modal fade" id="input_confirm">
    </div>
    <!--风控信息模态框-->
    <div class="modal fade" id="stcriskinfo_id" data-backdrop="static" tabindex="-1" role="dialog"
         aria-labelledby="myModalLabel" aria-hidden="true">
        <div class="modal-dialog" style="width: 90%;">
            <div class="modal-content " style=" background-color: #f5f5f5">
                <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>
                <table id="stcriskinfoTable"
                       style="table-layout: fixed;word-break:break-all; word-wrap:break-all;">

                </table>
            </div>
        </div>
    </div>

    <!-- Main content -->
    <section class="content" style="background-color: #000000">
        <div class="row" id="content" name="{{ customerid }}">
            <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 class="table table-bordered table-striped table-hover" id="RuleTable"
                                       style="table-layout: fixed;word-break:break-all; word-wrap:break-all;">
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="nav-tabs-custom right" style="background-color: #000000">
                    <ul class="nav nav-tabs">
                        <li id="stgpara" class="active"><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 active" 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"
                                       style="table-layout: fixed;word-break:break-all; word-wrap:break-all;">
                                </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"
                                       style="table-layout: fixed;word-break:break-all; word-wrap:break-all;">
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="nav-tabs-custom buttom" style="background-color: #000000">
                    <ul class="nav nav-tabs">
                        <li class="active"><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 active" id="fa-stgmm">
                            <div class=" mailbox-messages">
                                <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">
                                <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>


{% endblock %}

{% block scripts %}


    <script type="text/javascript">
        //风控信息
        //bstable渲染页面(固定写法)
        function InitBootstrapTable(my_url, my_table_id, my_columns, my_filename, stgid) {
            $('#' + my_table_id).bootstrapTable('destroy').bootstrapTable({
                url: my_url,
                method: 'get',
                columns: my_columns,
                {#height: 500,//固定高度,可以固定表头#}
                striped: true,
                cache: false,
                pagination: true,
                sortable: true,
                theadClasses: "thead-light",
                sortOrder: "asc",
                queryParams: function (pageRequest) {
                    pageRequest['ruleid'] = stgid;
                    return pageRequest;
                },
                sidePagination: "server",
                pageNumber: 1,
                pageSize: 20,
                pageList: [10, 25, 50, 100],
                minimumCountColumns: 2,
                clickToSelect: true,
                cardView: false,
                detailView: false,
                buttonsAlign: "right",
            })
        }

        // 风控信息
        my_columns = [
            {
                field: 'risktype',
                title: '风控类型'
            }, {
                field: 'riskindicator',
                title: '禁止指标',
                width: 200
            }, {
                field: 'risksource',
                title: '指标来源',
            }, {
                field: 'bondid',
                title: '代码',
            }, {
                field: 'direction',
                title: '方向',
            }, {
                field: 'settletype',
                title: '清算速度'
            }, {
                field: 'price',
                title: '报价%'
            }, {
                field: 'volume',
                title: '报量(万元)'
            }, {
                field: 'orderinserttime',
                title: '报单时间'
            }
        ];

        //风控信息
        function _stcriskinfoTable(id) {
            InitBootstrapTable("/trade/stcPriskinfo/", "stcriskinfoTable", my_columns, '0', id);
            //移除table-border和tbale-hover
            $("#stcriskinfoTable").removeClass("table-bordered");
            $("#stcriskinfoTable").removeClass("table-hover");
            $("#stcriskinfoTable").addClass("table-hov");
            $(".bootstrap-table").children().removeClass("fixed-table-toolbar");
            $('#stcriskinfo_id').modal("show");
        }


        var timer, clickFlag, stgtype, stgrefresh, stgStatus1, stgStatus2 = false;//外部变量,这三个变量是定时器是否存在的标志
        //初始化策略列表
        $("#RuleTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            height: 400,//固定高度,可以固定表头
            theadClasses: "thead-table",
            unique: "RuleID",
            sortable: true,
            // 策略列表table
            columns: [{
                field: 'RuleID',
                title: '策略ID',
                width: 50,
                sortOrder: "asc",
            }, {
                field: 'RuleName',
                title: '策略名称',
                width: 100
            }, {
                field: 'RuleRunStatus',
                title: '运行状态',
                width: 50,
                formatter: function (value, row, index) {
                    if (value === "1") {
                        return "停止"
                    } else if (value === "0") {
                        return "启动"
                    } else if (value === "01") {
                        return "启动中"
                    } else if (value === "11") {
                        return "停止中"
                    }
                }
            }, {
                field: 'LOption',
                title: '操作',
                width: 100,
                formatter: function (value, row, index) {
                    if (row.RuleRunStatus === "0") {
                        var start = "<span style='width: 50px' class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' disabled> <i class='fa'></i>启动</span> ";
                        var end = "<span style='width: 50px' onclick=\"endstg('" + row.RuleID + "','" + row.RuleName + "')\" type='button' class='btn btn-danger btn-xs btn-flat btn_operation'> <i class='fa'></i>停止</span>";
                    } else if (row.RuleRunStatus === "1") {
                        var start = "<span style='width: 50px' onclick=\"startstg('" + row.RuleID + "','" + row.RuleName + "')\" class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' > <i class='fa'></i>启动</span> ";
                        var end = "<span style='width: 50px' type='button' class='btn btn-danger btn-xs btn-flat btn_operation' disabled> <i class='fa'></i>停止</span>";
                    } else {
                        var start = "<span style='width: 50px' class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' disabled> <i class='fa'></i>启动</span> ";
                        var end = "<span style='width: 50px' type='button' class='btn btn-danger btn-xs btn-flat btn_operation' disabled> <i class='fa'></i>停止</span>";
                    }
                    return start + end + "&nbsp<span onclick=\"input_('" + row.RuleID + "','" + row.RuleName + "')\" type='button' class='btn btn-primary btn-xs btn-flat btn_operation'> <i class='fa'></i>人工录入</span>";
                }
            },
                {
                    field: 'LRisk',
                    title: '风控',
                    width: 50,
                    formatter: function (value, row, index) {
                        var stcriskinfo = "<span onclick=\"_stcriskinfoTable('" + row.RuleID + "')\" class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal'> <i class='fa'></i>风控信息</span> ";
                        return stcriskinfo
                    }
                }],
            onClickRow: function (row, $element, field) {
                //当前行的父元素tbody下的所有tr移除样式类
                $element.parent().children().removeClass("onclickrow")
                $element.addClass("onclickrow")
                var ruleid = row.RuleID
                var rule_status = row.RuleRunStatus
                //点击一行数据,初始化策略参数和策略指标
                RulePropIndic(ruleid, rule_status)
                //刚开始需要把上次的定时器取消掉,然后再进行定时任务。
                if (clickFlag) {
                    clearInterval(timer)
                }
                clickFlag = true;
                timer = setInterval(function () {
                    //记录刷新前的滚动条位置
                    var scrollPositionpara = $("#StgparaTable").bootstrapTable("getScrollPosition");
                    var scrollPositionind = $("#StgdicTable").bootstrapTable("getScrollPosition");
                    //先移除所有的数据,然后再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
                    //数据刷新之后,自动跳转到滚动条的位置。
                    setTimeout(function () {
                        $("#StgparaTable").bootstrapTable('scrollTo', scrollPositionpara)
                    }, 1)
                    setTimeout(function () {
                        $("#StgdicTable").bootstrapTable('scrollTo', scrollPositionind)
                    }, 1)
                }, 2000)
                //关闭定时器
                {#clearInterval(timer)#}
            }
        })


        //启动时的策略参数columns
        var columnStart = [{
            field: 'RuleID',
            title: '策略ID',
            visible: false
        }, {
            field: 'PropKey',
            title: '参数名'
        }, {
            field: 'PropValue',
            title: '参数值'
        }, {
            field: 'Description',
            title: '描述',
        }, {
            field: 'PropValueItems',
            title: '策略属性值选项',
            visible: false
        }, {
            field: 'PropType',
            title: '策略属性值类型',
            visible: false,
            formatter: function (value, row, index) {
                var val = unescape(value.replace(/\\u/g, "%u"));
                return val
            }
        }, {
            field: 'POption',
            title: '操作',
            formatter: function (value, row, index) {
                return "<span onclick=\"modify('" + row.RuleID + "'" + "," + "'" + row.PropKey + "'" +
                    "," + "'" + row.PropValue + "'" + "," + "'" + row.Description + "'" + "," + "'" + row.PropValueItems
                    + "')\" class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' data-target='#startstg'> <i class='fa'></i>编辑</span> "
            }
        }]

        //停止时的策略参数columns
        var columnEnd = [{
            field: 'RuleID',
            title: '策略ID',
            visible: false
        }, {
            field: 'PropKey',
            title: '参数名'
        }, {
            field: 'PropValue',
            title: '参数值'
        }, {
            field: 'Description',
            title: '描述',
        }, {
            field: 'PropValueItems',
            title: '策略属性值选项',
            visible: false
        }, {
            field: 'PropType',
            title: '策略属性值类型',
            visible: false,
            formatter: function (value, row, index) {
                var val = unescape(value.replace(/\\u/g, "%u"));
                return val
            }
        }, {
            field: 'POption',
            title: '操作',
            formatter: function (value, row, index) {
                return "<span class='btn btn-success btn-xs btn-flat btn_operation' data-toggle='modal' data-target='#startstg' disabled> <i class='fa'></i>编辑</span> "
            }
        }]

        //初始化策略指标
        $("#StgdicTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            height: 400,//固定高度,可以固定表头
            theadClasses: "thead-table",
            // 策略列表table
            columns: [{
                field: 'RuleID',
                title: '策略ID',
                visible: false
            }, {
                field: 'IndicatorKey',
                title: '指标名'
            }, {
                field: 'IndicatorValue',
                title: '指标值'
            }, {
                field: 'Description',
                title: '指标描述',
            }]
        })

        //初始化做市策略
        $("#StgMMTable").bootstrapTable('destroy').bootstrapTable({
            uniqueId: "RuleID",
            // 做市策略table
            height: 500,//固定高度,可以固定表头
            theadClasses: "thead-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",
            height: 500,//固定高度,可以固定表头
            theadClasses: "thead-table",
            // 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: "close",
                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 = [];
        var ws = $.trade("ws://" + PaperIP + ":" + PaperPORT + "/", {//
            OnFrontConnected: function () {
                $("#console").append("<br/>TD连接成功");
                sendMsg_login()
            },
            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);#}
                    $('#RuleTable').bootstrapTable('insertRow', {
                        index: 0,
                        row: 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() {
            ws.ReqUserLogin("1001", "123456");
        }


        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) {
            //将wrapper的style属性移除,因为该类有一个样式 height:auto,会形成两个滚动条。
            $(".wrapper").css("height", "1200px")
            initypestg()
            if (n == 1) {
                $('#fa-stgmm').addClass('active');
                $('#fa-stgcta').removeClass('active');
                clearInterval(stgtype)
                stgtype = setInterval(function () {
                    //记录刷新前的滚动条位置
                    var scrollPositionMM = $("#StgMMTable").bootstrapTable("getScrollPosition");
                    var scrollPositionCta = $("#StgCtaTable").bootstrapTable("getScrollPosition");
                    //先移除所有的数据,然后再append
                    $('#StgMMTable').bootstrapTable('removeAll');
                    $('#StgCtaTable').bootstrapTable('removeAll');
                    //bootstraptable渲染不同类型的策略
                    for (let key in rules) {
                        if (rules[key]["RuleType"] === "1") {
                            $('#StgMMTable').bootstrapTable('append', rules[key]);
                        } else if (rules[key]["RuleType"] === "2") {
                            $('#StgCtaTable').bootstrapTable('append', rules[key]);
                        }
                    }
                    //数据刷新之后,自动跳转到滚动条的位置。
                    setTimeout(function () {
                        $("#StgMMTable").bootstrapTable('scrollTo', scrollPositionMM)
                    }, 1)
                    setTimeout(function () {
                        $("#StgCtaTable").bootstrapTable('scrollTo', scrollPositionCta)
                    }, 1)
                }, 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]["RuleType"] === "1") {
                            $('#StgMMTable').bootstrapTable('append', rules[key]);
                        } else if (rules[key]["RuleType"] === "2") {
                            $('#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]["RuleType"] === "1") {
                    $('#StgMMTable').bootstrapTable('append', rules[key]);
                } else if (rules[key]["RuleType"] === "2") {
                    $('#StgCtaTable').bootstrapTable('append', rules[key]);
                }
            }
        }

        //策略参数和策略指标的初始化(点击某一行策略时触发)
        function RulePropIndic(ruleid, rulestatus) {
            if (rulestatus === "0") {
                //初始化策略参数
                $("#StgparaTable").bootstrapTable('destroy').bootstrapTable({
                    // 策略列表table
                    height: 400,//固定高度,可以固定表头
                    theadClasses: "thead-table",
                    columns: columnStart
                })
            } else if (rulestatus === "1") {
                //初始化策略参数
                $("#StgparaTable").bootstrapTable('destroy').bootstrapTable({
                    // 策略列表table
                    height: 400,//固定高度,可以固定表头
                    theadClasses: "thead-table",
                    columns: columnEnd
                })
            }
            //先移除所有的数据,然后再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));
        };

        var start_setTime1, start_setTime2 = null

        //启动策略
        function startstg(id, rulename) {
            var customerid = $("#content").attr("name")
            $("#RuleTable").bootstrapTable('updateByUniqueId', {
                id: id,
                row: {
                    RuleRunStatus: "01"
                }
            })
            ws.ReqOptionStg("start", id, customerid, "1", rulename);//flag为1时表示启动或者停止策略
            //启动后清空策略参数展示
            $('#StgparaTable').bootstrapTable('removeAll');
            $('#StgdicTable').bootstrapTable('removeAll');
            //清除已经存在的SetTimeout对象
            if (start_setTime1) {
                clearTimeout(start_setTime1)
                start_setTime1 = null
            } else if (start_setTime2) {
                clearTimeout(start_setTime2)
                start_setTime2 = null
            }
            //2s后轮询,判断状态是否异常
            start_setTime1 = setTimeout(function () {
                var stgobj = $('#RuleTable').bootstrapTable('getRowByUniqueId', id)
                if (stgobj.RuleRunStatus === "01") {
                    stgStatus1 = setInterval(function () {
                        console.log("轮询")
                        for (let key in rules) {
                            if (key === id && rules[key]["RuleRunStatus"] === "0") {
                                $('#RuleTable').bootstrapTable('updateRow', {
                                    index: id,
                                    row: rules[key]
                                })
                            }
                        }
                    }, 2000)
                } else {
                    clearInterval(stgStatus1)
                }
            }, 2000)

            //5s后清除轮询
            start_setTime2 = setTimeout(function () {
                var stgobj = $('#RuleTable').bootstrapTable('getRowByUniqueId', id)
                if (stgobj.RuleRunStatus === "01") {
                    clearInterval(stgStatus1)
                    $("#title_success").text("启动")
                    $("#msg_success").text(rulename + "启动失败,请检查策略!")
                    $("#oper_success").modal("show");
                    setTimeout(function () {
                        $("#oper_success").modal("hide");
                        window.location.reload()
                    }, 2000)
                }
            }, 5000)

        }


        var end_setTime1, end_setTime2 = null;

        //停止策略
        function endstg(id, rulename) {
            var customerid = $("#content").attr("name")
            $("#RuleTable").bootstrapTable('updateByUniqueId', {
                id: id,
                row: {
                    RuleRunStatus: "11"
                }
            })
            ws.ReqOptionStg("end", id, customerid, "1", rulename);
            //停止后清空策略参数展示
            $('#StgparaTable').bootstrapTable('removeAll');
            $('#StgdicTable').bootstrapTable('removeAll');
            //清除已经存在的SetTimeout对象
            if (end_setTime1) {
                clearTimeout(end_setTime1)
                end_setTime1 = null
            } else if (end_setTime2) {
                clearTimeout(end_setTime2)
                end_setTime2 = null
            }
            //2s后轮询,判断状态是否异常
            end_setTime1 = setTimeout(function () {
                var stgobj = $('#RuleTable').bootstrapTable('getRowByUniqueId', id)
                if (stgobj.RuleRunStatus === "11") {
                    stgStatus2 = setInterval(function () {
                        console.log("轮询")
                        for (let key in rules) {
                            if (key === id && rules[key]["RuleRunStatus"] === "1") {
                                $('#RuleTable').bootstrapTable('updateRow', {
                                    index: id,
                                    row: rules[key]
                                })
                            }
                        }
                    }, 2000)
                } else {
                    clearInterval(stgStatus2)
                }
            }, 2000)

            //5s后清除轮询
            end_setTime2 = setTimeout(function () {
                var stgobj = $('#RuleTable').bootstrapTable('getRowByUniqueId', id)
                if (stgobj.RuleRunStatus === "11") {
                    clearInterval(stgStatus2)
                    $("#title_success").text("停止")
                    $("#msg_success").text(rulename + "停止失败,请检查策略!")
                    $("#oper_success").modal("show");
                    setTimeout(function () {
                        $("#oper_success").modal("hide");
                        window.location.reload()
                    }, 2000)
                }
            }, 5000)
        }

        //编辑策略参数
        function modify(id, key, value, desc, valueitems) {
            $("#para_spaninfo").text("")
            $("#paraid").val(id)
            $("#paraname").val(key)
            $("#paravalue").val(value)
            $("#paradesc").val(desc)
            $("#paravalue").attr("name", valueitems); //为参数值设置name属性,值为valueitems,用于传到websockets传给userapi
            {#$("#paraname").attr("name", proptype); //为参数名设置name属性,值为proptype,用于传到websockets传给userapi#}
            $("#editstg").modal("show")
            {#return data#}
        }

        //隐藏编辑策略模态框
        function quit__() {
            $("#editstg").modal("hide");
            $("#input_").modal('hide')
        }

        //提交修改后的数据(策略参数)
        function sub() {
            var customerid = $("#content").attr("name")
            var paraid = $("#paraid").val();
            var paraname = $("#paraname").val();
            var paravalue = $("#paravalue").val();
            var paradesc = $("#paradesc").val();
            if (paravalue === "") {
                $("#para_spaninfo").text("策略参数不能为空!")
                return;
            }
            ws.ReqStgPara(customerid, paraid, paraname, paravalue, paradesc, "0",)
            $.ajax({
                type: "post",
                url: "/trade/alterpara/",
                data:
                    {
                        "ruleid": paraid,
                        "paraname": paraname,
                        "paravalue": paravalue,
                        "paradesc": paradesc,
                    },
                success: function (data) {
                    $("#editstg").modal("hide");
                    if (data === "y") {
                        $("#oper_success").modal("show");
                        setTimeout(function () {
                            $("#oper_success").modal("hide");
                        }, 2000)
                    } else {
                        $("#msg_success").text(data)
                        $("#oper_success").modal("show");
                        setTimeout(function () {
                            $("#oper_success").modal("hide");
                        }, 2000)
                    }
                }
            })
        }

        //人工录入的模态框
        function input_(ruleid, rulename) {
            $("input").val("");
            $("select").val("");
            $("#speedliqui").val("2");
            $("#vol_spaninfo").text("")
            $("#netprice_spaninfo").text("")
            $("#tranc_spaninfo").text("")
            $("#speedliqui_spaninfo").text("")
            $("#direction_spaninfo").text("")
            $("#bodecode_spaninfo").text("")
            //债券代码和方向的初始值
            for (let key in ruleProps) {
                if (key === ruleid + "indic_symbol") {
                    $("#bondcode").val(ruleProps[key]["IndicatorValue"])
                } else if (key === ruleid + "indic_direction") {
                    if (ruleProps[key]["IndicatorValue"] === "1") {
                        $("#direction").val("0")
                    } else if (ruleProps[key]["IndicatorValue"] === "0") {
                        $("#direction").val("1")
                    }
                }
            }
            $("#manual-ruleid").val(ruleid)
            {#$("#manual-rulename").val(encodeURI(rulename))#}
            $("#manual-rulename").val(rulename)
            $("#input_").modal("show")
        }

        //4位小数校验,不足补0
        function checkfour(inp, typ) {
            var inp_split = inp.split(".");
            if (inp_split.length > 2) {
                if (typ === "tranc") {
                    $("#tranc_spaninfo").text("成交价输入格式有误!")
                } else if (typ === "netprice") {
                    $("#netprice_spaninfo").text("净价输入格式有误!")
                }
                return "n"
            } else if (inp_split.length === 1) {
                return inp + ".0000"
            } else {
                var l = inp_split[1].length
                var a = 4 - l;
                if (a > 0 && a !== 0) {
                    for (let i = 0; i < a; i++) {
                        inp += "0"
                    }
                }
                return inp
            }

        }


        //人工录入模态框的提交
        function input_sub() {
            //所有的提示信息都清空
            $("#vol_spaninfo").text("")
            $("#netprice_spaninfo").text("")
            $("#tranc_spaninfo").text("")
            $("#speedliqui_spaninfo").text("")
            $("#direction_spaninfo").text("")
            $("#bodecode_spaninfo").text("")

            const bondcode = $("#bondcode").val();
            const direction = $("#direction").val();
            const speedliqui = $("#speedliqui").val();
            var tranc = $("#tranc").val();
            var netprice = $("#netprice").val();
            const vol = $("#vol").val()
            //点击提交首先检验
            if (bondcode === "") {
                $("#bodecode_spaninfo").text("债券代码不能为空!")
                return;
            } else if (direction === "") {
                $("#direction_spaninfo").text("方向不能为空!")
                return;
            } else if (speedliqui === "") {
                $("#speedliqui_spaninfo").text("清算速度不能为空!")
                return;
            } else if (tranc === "") {
                $("#tranc_spaninfo").text("成交价不能为空!")
                return;
            } else if (vol === "") {
                $("#vol_spaninfo").text("成交量不能为空!")
                return;
            } else if (parseFloat(tranc).toString() === "NaN") {
                $("#tranc_spaninfo").text("成交价必须为数字!")
                return;
            } else if (parseFloat(netprice).toString() === "NaN") {
                $("#netprice_spaninfo").text("净价必须为数字!")
                return;
            } else if (/^\d+$/.test(vol) === false || parseInt(vol) > 100000 || parseInt(vol) < 1) {
                $("#vol_spaninfo").text("成交量必须为1-100000的整数!")
                return;
            }
            //id,name传给后台
            var ruleid = $("#manual-ruleid").val()
            var rulename = $("#manual-rulename").val()
            var flag1 = checkfour(tranc, "tranc")
            var flag2 = checkfour(netprice, "netprice")
            if (flag1 === "n" || flag2 === "n") {
                return;
            } else {
                tranc = flag1;
                netprice = flag2;
            }

            const direction_val = $("#direction").find("option[value=" + direction + "]").text().replace(/\s+/g, "");
            const speedliqui_val = $("#speedliqui").find("option[value=" + speedliqui + "]").text().replace(/\s+/g, "");
            var input_confirm = '<div class="modal-dialog">\n' +
                '            <div class="modal-content">\n' +
                '                <div class="modal-header">\n' +
                '                    <h4 class="modal-title">人工录入确认</h4>\n' +
                '                </div>\n' +
                '                <div class="modal-body">\n' +
                '                    <form>\n' + '<div style="display: none">\n' +
                '                            <input id="cmanual-ruleid" value="' + ruleid + '">\n' +
                '                            <input id="cmanual-rulename" value="' + rulename + '">\n' +
                '                        </div>' +
                '                        <div style="margin-top:3%; display: block">\n' +
                '                            <label>债券代码*</label>\n' +
                '                            <input class="opts conf" id="cbondcode" name="bondcode" type="text"\n' +
                '                                   value="' + bondcode + '">\n' +
                '                        </div>\n' +
                '                        <div style="margin-top:3%">\n' +
                '                            <label>方向*</label>\n' +
                '                            <input class="opts conf" id="cdirection" name="' + direction + '" type="text"\n' +
                '                                   value="' + direction_val + '">\n' +
                '                        </div>\n' +
                '                        <div style="margin-top:3%">\n' +
                '                            <label>清算速度*</label>\n' +
                '                            <input class="opts conf" id="cspeedliqui" name="' + speedliqui + '" type="text" value="' + speedliqui_val + '">\n' +
                '                        </div>\n' +
                '                        <div style="margin-top:3%; display: block">\n' +
                '                            <label>成交价(%)*</label>\n' +
                '                            <input class="opts conf" id="ctranc" name="tranc" type="text"\n' +
                '                                   value="' + tranc + '">\n' +
                '                        </div>\n' +
                '                        <div style="margin-top:3%; display: block">\n' +
                '                            <label>净价(元)*</label>\n' +
                '                            <input class="opts conf" id="cnetprice" name="netprice" type="text"\n' +
                '                                   value="' + netprice + '">\n' +
                '                        </div>\n' +
                '                        <div style="margin-top:3%; display: block">\n' +
                '                            <label>成交量(%)*</label>\n' +
                '                            <input class="opts conf" id="cvol" name="vol" type="text"\n' +
                '                                   value="' + vol + '">\n' +
                '                        </div>\n' +
                '                        <hr>\n' +
                '                        <div style="height: 20px; display: block">\n' +
                '                            <div style="padding-left:120px; float: left;">\n' +
                '                            <span class="btn-cancel btn-stc"\n' +
                '                                  onclick="quit__inp()">取消</span>\n' +
                '                            </div>\n' +
                '                            <div style="padding-left:5px;float: left;">\n' +
                '                            <span class="btn-confirm btn-stc"\n' +
                '                                  onclick="hand_sub()">提交</span>\n' +
                '                            </div>\n' +
                '                        </div>\n' +
                '                    </form>\n' +
                '                </div>\n' +
                '            </div>\n' +
                '        </div>'

            $("#input_confirm").append(input_confirm)
            $("#input_confirm").modal("show")


        }


        //人工录入后台发送请求
        function hand_sub() {
            const bondcode = $("#cbondcode").val();
            const direction_val = $("#cdirection").attr('name');
            const speedliqui_val = $("#cspeedliqui").attr('name');
            var tranc = $("#ctranc").val();
            var netprice = $("#cnetprice").val();
            const vol = $("#cvol").val()
            var ruleid = $("#cmanual-ruleid").val()
            var rulename = $("#cmanual-rulename").val()
            var customerid = $("#content").attr("name")
            $.ajax({
                type: "post",
                url: "/trade/hand_input/",
                data:
                    {
                        "bondcode": bondcode,
                        "direction_val": direction_val,
                        "speedliqui_val": speedliqui_val,
                        "tranc": tranc,
                        "netprice": netprice,
                        "vol": vol,
                        "ruleid": ruleid,
                        "rulename": rulename,
                        "customerid": customerid
                    },
                success: function (data) {
                    $("#input_").modal("hide");
                    $("#input_confirm").modal("hide");
                    $("#title_success").text("人工录入")
                    if (data === "y") {
                        $("#msg_success").text("录入成功!")
                        $("#oper_success").modal("show");
                        setTimeout(function () {
                            $("#oper_success").modal("hide");
                        }, 2000)
                    } else {
                        $("#msg_success").text(data)
                        $("#oper_success").modal("show");
                        setTimeout(function () {
                            $("#oper_success").modal("hide");
                        }, 2000)
                    }
                }
            })

        }

        //隐藏确认框
        function quit__inp() {
            $("#input_confirm").modal("hide")
            $("#input_confirm").html("")
        }

        $(function () {
            initypestg()
            $('#fa-stgmm').addClass('active');
            $('#fa-stgcta').removeClass('active');
            clearInterval(stgtype);
            stgtype = setInterval(function () {
                //记录刷新前的滚动条位置
                var scrollPositionMM = $("#StgMMTable").bootstrapTable("getScrollPosition");
                var scrollPositionCta = $("#StgCtaTable").bootstrapTable("getScrollPosition");
                //先移除所有的数据,然后再append
                $('#StgMMTable').bootstrapTable('removeAll');
                $('#StgCtaTable').bootstrapTable('removeAll');
                //bootstraptable渲染不同类型的策略
                for (let key in rules) {
                    if (rules[key]["RuleType"] === "1") {
                        $('#StgMMTable').bootstrapTable('append', rules[key]);
                    } else if (rules[key]["RuleType"] === "2") {
                        $('#StgCtaTable').bootstrapTable('append', rules[key]);
                    }
                }
                //数据刷新之后,自动跳转到滚动条的位置。
                setTimeout(function () {
                    $("#StgMMTable").bootstrapTable('scrollTo', scrollPositionMM)
                }, 1)
                setTimeout(function () {
                    $("#StgCtaTable").bootstrapTable('scrollTo', scrollPositionCta)
                }, 1)
            }, 2000)
            /**
             clearInterval(stgrefresh);
             stgrefresh = setInterval(function () {
                $('#RuleTable').bootstrapTable('removeAll');
                for (let key in rules) {
                    $("#RuleTable").bootstrapTable("append", rules[key]);
                }
            }, 2000);
             **/
        })


    </script>
    <style>
        {#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);
        }


        .tab-content {
            height: 380px;
        }

        .stginfo {
            height: 400px;
        }

        .onclickrow {
            background-color: #444444;
        }

        .opts {
            background-color: white;
            margin-left: 10px;
        }

        .table-hov > tbody > tr:hover {
            background-color: #eee;
            cursor: pointer;
        }


    </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"
            };
            _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).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, customerid, flag, rulename) {
                console.log("策略名称", encodeURI(rulename))
                this.ws.send(FTD_TID_ReqOptionStg, {
                    "optype": optype,
                    "stgid": ruleid,
                    "customerid": customerid,
                    "flag": flag,
                    "rulename": encodeURI(rulename)
                })
            };

            //策略参数发送到websocket
            tradeWS.ReqStgPara = function (customerid, ruleid, key, value, desc) {
                console.log(encodeURI(desc));
                this.ws.send(FTD_TID_ReqStgPara, {
                    "customerid": customerid,
                    "stgid": ruleid,
                    "stgname": encodeURI(key),
                    "stgvalue": encodeURI(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);



后台服务

# encoding: UTF-8

from time import sleep

from hft_api import HftApi
import time
import os
import re
import json
import threading
import copy
import multiprocessing
from websocket_server import WebsocketServer
import shutil

global signal
import datetime
from enum import Enum
from process_manager import process_manager
import pandas as pd
from sqlalchemy import create_engine
import urllib.parse
import socket
import WebsocketLog
import configparser

## 配置信息
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
config_init = configparser.ConfigParser()
config_init.read(os.path.join(BASE_DIR, 'config.ini'))


# 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 HFTMdApi(HftApi):

    def __init__(self, Queue1):
        """Constructor"""
        super(HFTMdApi, 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)

    # ----------------------------------------------------------------------
    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)

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

    def onRtnRuleProp(self, data):
        """策略属性变化回报"""
        package = {'Tid': 0x00001044, 'data': data}
        self.save_as_json(package)
        # 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)

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

    # 在C++环境中创建MdApi对象,传入参数是希望用来保存.con文件的地址
    # @param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录
    # @return 创建出的UserApi
    # modify for udp marketdata
    def CreateFtdcMdApi(self):
        self.createUserApi()

    # 删除接口对象本身
    # @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'] = config_init.get("LoginReq", 'CustomerID')
        loginReq['Password'] = config_init.get("LoginReq", 'Password')
        loginReq['MacAddress'] = config_init.get("LoginReq", 'MacAddress')
        loginReq['SubInstrumentMethod'] = config_init.get("LoginReq", 'SubInstrumentMethod')
        loginReq['IsRule'] = int(config_init.get("LoginReq", 'IsRule'))
        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()
        tkernel = config_init.get("TKernel", "ip")
        self.RegisterFront(tkernel)
        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):
        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__()
        # 数据库
        # sql_user = 'root'
        # sql_password = 'XCL29hao'
        # sql_host = '111.231.16.33'
        # sql_port = 3306
        # sql_database = 'strategy'

        sql_user = config_init.get("MySql", "user")
        sql_password = config_init.get("MySql", "password")
        sql_host = config_init.get("MySql", "host")
        sql_port = config_init.get("MySql", "port")
        sql_database = config_init.get("MySql", 'name')

        # 数据库连接
        self.engine_str = f"mysql+mysqlconnector://{sql_user}:{sql_password}@{sql_host}:{sql_port}/{sql_database}?charset=utf8"
        self.engine = create_engine(self.engine_str)
        self.db_run = config_init.get("DBRun", "db_run")
        ipstr = os.popen(""" ifconfig | sed -n "2p" """).readlines()[0]
        self.ip_address = re.findall("((?<![\.\d])(?:\d{1,3}\.){3}\d{1,3}(?![\.\d]))", ipstr)[0]
        # self.ip_address = socket.gethostbyname(socket.getfqdn(socket.gethostname()))
        # self.ip_address = "172.16.78.228"
        self.total_dict = {}  # 全量数据
        self.work_path = os.getcwd()
        # 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("行情定阅成功")
            elif msg["Tid"] == 8450:
                print("点击了修改策略参数按钮")
                try:
                    customerid = msg["data"]["customerid"]
                    print("策略参数customerid", customerid)
                    ruleReq2 = {}  # 创建一个空字典
                    ruleReq2['RuleID'] = int(msg["data"]["stgid"])  # 策略代码
                    ruleReq2['PropKey'] = urllib.parse.unquote(msg["data"]["stgname"]).encode('gbk')  # 策略属性键
                    ruleReq2['PropValue'] = urllib.parse.unquote(msg["data"]["stgvalue"]).encode('gbk')  # 策略属性值
                    ruleReq2['PropType'] = "1"  # 策略属性值类型
                    ruleReq2['PropValueItems'] = "1"  # 策略属性值选项
                    ruleReq2['Description'] = urllib.parse.unquote(msg["data"]["stgdesc"]).encode('gbk')  # 描述
                    print("修改参数:", ruleReq2)
                    api.ReqUpdateRuleProp(ruleReq2)
                    WebsocketLog.websocketlog(customerid, "modifypara", "", ruleReq2['RuleID'])
                    print("策略参数修改完毕")
                except Exception as e:
                    print("策略参数修改失败", e)
            elif msg["Tid"] == 4097:
                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
            elif msg["Tid"] == 8449:
                try:
                    optype = msg['data']["optype"]
                    stgid = msg['data']['stgid']
                    customerid = msg['data']['customerid']
                    flag = msg['data']['flag']
                    rulename = urllib.parse.unquote(msg['data']['rulename'])
                    if optype == "end":
                        # 一键撤单的日志
                        if flag == "2":
                            WebsocketLog.websocketlog(customerid, "korder", "", "")
                        else:
                            self.init_run(6, stgid)
                            # 策略停止,写入日志
                            if flag == "1":
                                WebsocketLog.websocketlog(customerid, "end", rulename, stgid)
                    elif optype == "start":
                        self.init_run(5, stgid)
                        WebsocketLog.websocketlog(customerid, "start", rulename, stgid)
                        # print("待启动发送成功!!")
                except Exception as e:
                    print(e)

        def onmessage(client, server, msg):
            try:
                jsonObject = json.loads(msg)
                print("前端传来了:", jsonObject)
                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": "登陆失败"}}))
            except Exception as e:
                print("123", e)

        def sendDataToAllClient():
            while True:
                jsonData = self.tid_Queue.get()
                print("启动后收到:", jsonData)
                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']['PropKey']] = jsonData
                elif jsonData["Tid"] == FTD_Tid_RtnRuleIndicator:  # 指标4165
                    self.total_dict[str(jsonData['data']['RuleID']) + '_' + jsonData['data']['IndicatorKey']] = jsonData

                # 给所有的客户端都发数据
                server.send_message_to_all(json.dumps(jsonData))

        ### linux服务器上的ip地址
        server = WebsocketServer(int(config_init.get("WebSocketAddr", "port")),
                                 host=config_init.get("WebSocketAddr", "ip"))
        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错误
        '''
        process_main = process_manager()

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

        try:
            # #读取需要启停的进程
            content = f'select a.RunStatus,a.EnvID,a.StgID,a.RunPath from {self.db_run} a, t_environment b \
            where a.EnvID = b.EnvID and b.IP = "{self.ip_address}" and a.StgID = {stg_id} '
            sql_df = pd.read_sql_query(content, self.engine)
            if len(sql_df) == 0:
                return 0

            path = sql_df['RunPath'].tolist()[0]
            env_id = sql_df['EnvID'].tolist()[0]
            # path="/usr/local/process/50002/50002"
            # env_id=8
            # 类型转换
            run_status = int(run_status)
            stg_id = str(stg_id)
            #            # 复制exe到指定路径
            #            strategy_path = ('/').join(path.split('/')[:-1])
            #            file_path = strategy_path + '/strategy.ini'
            #            target_path = self.work_path + '/strategy.ini'
            #            shutil.copyfile(file_path, target_path)

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

                if flag:
                    # 更新run表
                    try:
                        content = f'update {self.db_run} set RunStatus = "1"\
                        , StartTime = \
                        "{datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")}" \
                        , EndTime = "" \
                        where StgID = {stg_id} and EnvId = {env_id}'
                        # print("启动进程", content)
                        pd.read_sql_query(content, self.engine, chunksize=1)
                        print("修改数据库状态成功!")
                    except Exception as e:
                        print("启动进程出错", e)
                        # 终止进程

            # 点击停止后,向queue中put数据,给useapi传数据
            elif run_status == 6:  # run_status_enum.待停止.value:
                try:
                    package = {"RuleID": int(stg_id), "RuleOperType": "1"}
                    api.ReqUpdateRuleStatus(package)
                except Exception as e:
                    print("终止进程出错", e)
                    pass

        except Exception as e:
            print("init_run 出错", e)


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


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

        p1 = multiprocessing.Process(target=HFTMdApi, args=(tid_Queue,))
        global api
        api = HFTMdApi(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("父进程结束")
    except Exception as e:
        print(e)


if __name__ == '__main__':
    main()

Django中使用WebSocket实现系统消息通知可以通过以下步骤实现: 1. 安装Django Channels和asgiref ```bash pip install channels asgiref ``` 2. 创建一个Django应用程序 ```bash python manage.py startapp notifications ``` 3. 创建一个WebSocket路由 在`notifications`应用程序中创建一个`routing.py`文件,添加以下内容: ```python from django.urls import re_path from . import consumers websocket_urlpatterns = [ re_path(r'ws/notifications/$', consumers.NotificationConsumer.as_asgi()), ] ``` 4. 创建一个WebSocket消费者 在`notifications`应用程序中创建一个`consumers.py`文件,添加以下内容: ```python import asyncio import json from channels.consumer import AsyncConsumer from channels.db import database_sync_to_async from django.contrib.auth.models import User class NotificationConsumer(AsyncConsumer): async def websocket_connect(self, event): await self.send({ "type": "websocket.accept" }) user = self.scope["user"] if user.is_authenticated: await self.channel_layer.group_add( f"user_{user.id}", self.channel_name ) async def websocket_receive(self, event): user = self.scope["user"] if user.is_authenticated: data = json.loads(event["text"]) message = data["message"] await self.create_message(user, message) await self.channel_layer.group_send( f"user_{user.id}", { "type": "user.message", "message": message } ) async def websocket_disconnect(self, event): user = self.scope["user"] if user.is_authenticated: await self.channel_layer.group_discard( f"user_{user.id}", self.channel_name ) @database_sync_to_async def create_message(self, user, message): user = User.objects.get(id=user.id) user.notifications.create(message=message) ``` 5. 配置WebSocket路由 在`settings.py`文件中添加以下内容: ```python ASGI_APPLICATION = 'project_name.routing.application' CHANNEL_LAYERS = { "default": { "BACKEND": "channels.layers.InMemoryChannelLayer" } } ROOT_URLCONF = 'project_name.urls' INSTALLED_APPS = [ ... 'channels', 'notifications', ] ``` 6. 创建一个JavaScript文件 在`static/js/notifications.js`文件中添加以下内容: ```javascript var socket = new WebSocket("ws://" + window.location.host + "/ws/notifications/"); socket.onmessage = function(event) { var message = JSON.parse(event.data)["message"]; alert(message); } ``` 7. 在模板中引入JavaScript文件 在需要使用WebSocket的模板中添加以下内容: ```html {% load static %} <script src="{% static 'js/notifications.js' %}"></script> ``` 现在,当用户登录并连接到WebSocket时,他们将加入名为`user_<user_id>`的组。当用户收到新消息时,消息将保存到数据库中,并通过WebSocket发送到所有连接到该组的用户。在前端,我们使用JavaScript来处理接收到的消息,这里简单地使用了一个警报框来显示消息,你可以改为使用其他的UI库。 希望这个教程能够帮助你实现DjangoWebSocket的消息通知功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值