Browse Source

1.添加机器人详情余额变动时参数
2.添加批量删除apikey
3.添加币对打分排行页面

DESKTOP-NE65RNK\Citrus_limon 1 năm trước cách đây
mục cha
commit
83880cd500

+ 21 - 8
src/api/index.ts

@@ -30,8 +30,6 @@ export const update_user_password = (params: any, callback: any) => {
   });
 };
 
-
-
 // 日志管理
 // 日志管理-登录日志
 export const get_login_log_list = (params: any, callback: any) => {
@@ -53,6 +51,12 @@ export const get_remaining = (params: any, callback: any) => {
     if (data) callback && callback(data);
   });
 };
+// 账户信息-账户余额详情
+export const get_remaining_detail = (params: any, callback: any) => {
+  return http.request("/api/remaining/listDetail", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
 
 // 机器人管理
 // 机器人管理-机器人列表
@@ -62,13 +66,13 @@ export const get_robot_list = (params: any, callback: any) => {
   });
 };
 // 机器人管理-机器人详情
-export const get_robot_detail  = (params: any, callback: any) => {
+export const get_robot_detail = (params: any, callback: any) => {
   return http.request("/api/robot/findById", "get", params).then((data) => {
     if (data) callback && callback(data);
   });
 };
 // 机器人管理-机器人日志
-export const get_robot_logs  = (params: any, callback: any) => {
+export const get_robot_logs = (params: any, callback: any) => {
   return http.request("/api/robot/getRobotLog", "get", params).then((data) => {
     if (data) callback && callback(data);
   });
@@ -439,6 +443,19 @@ export const get_ia_exchanges = (params: any, callback: any) => {
     if (data) callback && callback(data);
   });
 };
+// 情报中心-选币排行
+export const get_symbols_rank = (params: any, callback: any) => {
+  return http.request("/rk/get_rank_list", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+// 情报中心-选币排行
+export const get_exchange_rank = (params: any, callback: any) => {
+  return http.request("/rk/get_exchanges", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+
 
 // 资金曲线
 // 资金曲线-按用户
@@ -468,8 +485,6 @@ export const get_exchange_pair_profit_statistics = (params: any, callback: any)
   });
 };
 
-
-
 // 系统管理
 // 用户管理-用户列表
 export const get_user_list = (params: any, callback: any) => {
@@ -588,8 +603,6 @@ export const get_menu_all = (params: any, callback: any) => {
   });
 };
 
-
-
 // 数据收集-数据交易日志
 export const get_acquire_log = (params: any, callback: any) => {
   return http.request("/api/acquireULog/getPage", "get", params).then((data) => {

+ 9 - 3
src/router/routes.ts

@@ -71,11 +71,17 @@ const routes: Array<RouteRecordRaw> = [
         meta: { title: "波动率指标", keepAlive: true },
       },
       {
-        path: "/indicator/sybmol_filter",
-        name: "IndicatorSybmolFilter",
-        component: () => import("@/views/indicator/sybmol_filter/index.vue"),
+        path: "/indicator/symbol_filter",
+        name: "IndicatorSymbolFilter",
+        component: () => import("@/views/indicator/symbol_filter/index.vue"),
         meta: { title: "币对筛选器", keepAlive: true },
       },
+      {
+        path: "/indicator/symbol_rank",
+        name: "IndicatorSymbolRank",
+        component: () => import("@/views/indicator/symbol_rank/index.vue"),
+        meta: { title: "币对排行", keepAlive: true },
+      },
       {
         path: "/statistic/balance_user",
         name: "StatisticBalanceUser",

+ 17 - 8
src/views/bot/manage/detail.vue

@@ -25,7 +25,7 @@
           <span class="card-title">净值图</span>
         </template>
         <template v-slot:body>
-          <div class="profit-chart" id="profit-chart" ref="balanceChartRef"></div>
+          <div class="profit-chart" ref="balanceChartRef"></div>
         </template>
       </lay-card>
     </div>
@@ -49,11 +49,11 @@
   <LogText ref="logtextRef" />
 </template>
 <script lang="ts" setup name="BotManageDetail">
-import { ref, reactive, onUnmounted, shallowRef } from "vue";
+import { ref, reactive, onMounted, onUnmounted, shallowRef } from "vue";
 import { useRoute } from "vue-router";
 import * as echarts from "echarts";
 import LogText from "./components/LogText.vue";
-import { get_robot_detail, get_robot_logs, get_remaining } from "@/api";
+import { get_robot_detail, get_robot_logs, get_remaining_detail } from "@/api";
 
 const ROBOT_STATUS: any = reactive({
   STOPPED: "已停止",
@@ -107,20 +107,19 @@ const getRobotDetail = () => {
     }
   });
 };
-getRobotDetail();
 
 // 获取账户余额
 const getBalanceInfo = (id: number) => {
   const params = { id: id };
   pageConfig.loading = true;
-  get_remaining(params, (data: any) => {
+  get_remaining_detail(params, (data: any) => {
     pageConfig.loading = false;
     if (data.code == 200) {
       balanceList.value = data.data;
 
       const xData = data.data.map((item: any) => item.creationTime);
-      const sData = data.data.map((item: any) => item.balance);
-      const yMinData = Math.min(sData);
+      const sData = data.data.map((item: any) => [item.creationTime, item.afterU, item.changeU, item.pair, item.openNum, item.closeNum]);
+      const yMinData = Math.min(sData.map((item: any) => item[1]));
 
       !balanceChart.value
         ? initChart(data.data)
@@ -177,13 +176,15 @@ const handlePageInfo = (data: any) => {
 };
 
 const initChart = (data: any) => {
+  if (balanceChart.value != null && !balanceChart.value.isDisposed()) echarts.dispose(balanceChart.value);
+
   balanceChart.value = echarts.init(balanceChartRef.value);
 
   window.removeEventListener("resize", () => balanceChart.value.resize());
   window.addEventListener("resize", () => balanceChart.value.resize());
 
   const xData = data.map((item: any) => item.creationTime);
-  const sData = data.map((item: any) => item.balance);
+  const sData = data.map((item: any) => [item.creationTime, item.afterU, item.changeU, item.pair, item.openNum, item.closeNum]);
   const yMinData = Math.min(sData);
 
   const balanceChartOption = {
@@ -192,6 +193,10 @@ const initChart = (data: any) => {
       axisPointer: {
         type: "cross",
       },
+      formatter: (params: any) => {
+        let info = params[0];
+        return `${info.marker}${info.seriesName}<br/>时间:${info.value[0]} <br/>余额:${info.value[1]}<br/>收益:${info.value[2]}<br/>币对:${info.value[3]}<br/>开仓:${info.value[4]}<br/>平仓:${info.value[5]}`;
+      },
     },
     dataZoom: [
       {
@@ -229,6 +234,10 @@ timer.value = setInterval(() => {
   getLogsInfo();
 }, 5000);
 
+onMounted(() => {
+  getRobotDetail();
+});
+
 onUnmounted(() => {
   window.removeEventListener("resize", () => balanceChart.value.resize());
   clearInterval(timer.value);

+ 20 - 4
src/views/exchange/apikey/index.vue

@@ -6,6 +6,7 @@
     <template v-slot:extra>
       <lay-button class="card-button" v-if="apiList?.includes('/userProof/save')" @click="handleBatch()">批量添加ApiKey</lay-button>
       <lay-button class="card-button" v-if="apiList?.includes('/userProof/save')" @click="handleUpdate()">添加ApiKey</lay-button>
+      <lay-button class="card-button" v-if="apiList?.includes('/userProof/delete')" @click="handleDelete(selectedKeys)">批量删除ApiKey</lay-button>
     </template>
 
     <template v-slot:body>
@@ -20,11 +21,20 @@
         </lay-form>
       </div>
       <div>
-        <lay-table :page="tablePage" :columns="columns" resize :data-source="dataSource" :loading="pageConfig.loading" @change="handleCurrentChange">
+        <lay-table
+          :page="tablePage"
+          :columns="columns"
+          resize
+          id="userProofId"
+          :data-source="dataSource"
+          v-model:selected-keys="selectedKeys"
+          :loading="pageConfig.loading"
+          @change="handleCurrentChange"
+        >
           <template v-slot:operator="{ row }">
             <lay-space>
               <TableButton v-if="apiList?.includes('/userProof/update')" text="编辑" @click="handleUpdate(row)" />
-              <TableButton v-if="apiList?.includes('/userProof/delete')" type="danger" text="删除" @click="handleDelete(row)" />
+              <TableButton v-if="apiList?.includes('/userProof/delete')" type="danger" text="删除" @click="handleDelete([row.userProofId])" />
             </lay-space>
           </template>
         </lay-table>
@@ -70,6 +80,7 @@ interface TablePage {
 }
 const tablePage: TablePage = reactive({ current: 1, limit: 20, total: 0, limits: [20, 50, 100, 200, 500] });
 const columns = ref([
+  { title: "选项", width: "44px", type: "checkbox" },
   { title: "名称", key: "name" },
   { title: "交易所", key: "exchangeName", ellipsisTooltip: true },
   { title: "API", key: "accessKey", ellipsisTooltip: true },
@@ -86,10 +97,14 @@ const columns = ref([
   },
 ]);
 let dataSource = ref([]);
+let selectedKeys = ref([]);
 
 // 请求ApiKey列表
 const getPageInfo = (isSearch?: boolean) => {
-  if (isSearch) pageParams.pageNum = 1;
+  if (isSearch) {
+    pageParams.pageNum = 1;
+    selectedKeys.value = [];
+  }
   pageConfig.loading = true;
   get_apikey_list(pageParams, (data: any) => {
     pageConfig.loading = false;
@@ -115,13 +130,14 @@ const handleBatch = async () => {
 const handleDelete = async (value: any) => {
   let result = await proxy.$waitingConfirm("是否确认删除该ApiKey?");
   if (!result) return;
-  let params = [value.userProofId];
+  let params = value;
   pageConfig.loading = true;
   delete_apikey(params, (data: any) => {
     pageConfig.loading = false;
     if (data.code == 200) {
       proxy.$message(`删除成功!`);
       getPageInfo();
+      selectedKeys.value = selectedKeys.value.filter((item) => !value.includes(item));
     }
   });
 };

+ 31 - 23
src/views/indicator/msv/index.vue

@@ -130,6 +130,7 @@ const initChart = (data: any) => {
   const liqsData = data.liqs;
   const eprsData = data.eprs;
   const sigmasData = data.sigmas;
+  const sigmasMasData = data.sigma_mas;
   const chartOption = {
     title: [
       {
@@ -204,33 +205,29 @@ const initChart = (data: any) => {
       trigger: "axis",
       axisPointer: {
         type: "cross",
-        lineStyle: {
-          type: "dashed",
-          width: 1,
-        },
       },
       formatter: (params: any) => {
         if (params.length === 0) return "";
         let result = "";
-        params.forEach((param: any) => {
-          let time = dayjs(param.name * 1).format("YYYY-MM-DD HH:mm:ss.SSS");
-          if (param.seriesIndex == 0) {
-            // 主图的 tooltip
-            let volatilities = param.value[1];
-            let dissociation = unitConverts(param.value[2]);
-            result = `时间:${time}<br/>波动幅度:${volatilities}%<br/>强度:${dissociation} USDT<br/>`;
-          } else if (param.seriesIndex == 1) {
-            // 副图的 tooltip
-            result = `时间:${time}<br/>行情推动量:${param.value[1]}K<br/>`;
-          } else if (param.seriesIndex == 2) {
-            // 副图的 tooltip
-            result = `时间:${time}<br/>预期利润:${param.value[1]}%<br/>`;
-          }else if (param.seriesIndex == 3) {
-            // 副图的 tooltip
-            result = `时间:${time}<br/>sigma:${param.value[1]}<br/>`;
-          }
-        });
-
+        let param = params[0];
+        let time = dayjs(param.name * 1).format("YYYY-MM-DD HH:mm:ss.SSS");
+        if (param.seriesIndex == 0) {
+          // 主图的 tooltip
+          let volatilities = param.value[1];
+          let dissociation = unitConverts(param.value[2]);
+          result = `时间:${time}<br/>波动幅度:${volatilities}%<br/>强度:${dissociation} USDT<br/>`;
+        } else if (param.seriesIndex == 1) {
+          // 副图的 tooltip
+          result = `时间:${time}<br/>预期利润:${param.value[1]}%<br/>`;
+        } else if (param.seriesIndex == 2) {
+          // 副图的 tooltip
+          result = `时间:${time}<br/>行情推动量:${param.value[1]}K<br/>`;
+        } else if (param.seriesIndex == 3) {
+          let sigma = params[0]?.value[1] || 0;
+          let sigmaMas = params[1]?.value[1];
+          // 副图的 tooltip
+          result = `时间:${time}<br/>sigma:${sigma}${sigmaMas ? "<br/>Ma(sigma, 100):" + sigmaMas + "<br/>" : ""}`;
+        }
         return result;
       },
     },
@@ -338,6 +335,8 @@ const initChart = (data: any) => {
       {
         type: "line",
         sampling: "lttb",
+        showSymbol: false,
+        name: "123",
         xAxisIndex: 3,
         yAxisIndex: 3,
         itemStyle: {
@@ -345,6 +344,15 @@ const initChart = (data: any) => {
         },
         data: sigmasData,
       },
+      {
+        type: "line",
+        sampling: "lttb",
+        showSymbol: false,
+        name: "123",
+        xAxisIndex: 3,
+        yAxisIndex: 3,
+        data: sigmasMasData,
+      },
     ],
   };
   msvChart.value.setOption(chartOption);

+ 0 - 0
src/views/indicator/sybmol_filter/index.vue → src/views/indicator/symbol_filter/index.vue


+ 192 - 0
src/views/indicator/symbol_rank/index.vue

@@ -0,0 +1,192 @@
+<template>
+  <lay-card class="custom-card">
+    <template v-slot:title>
+      <span class="card-title">币对分数排名</span>
+    </template>
+    <template v-slot:body>
+      <lay-loading class="custom-loading" :loading="pageConfig.loading">
+        <div class="custom-form-layout">
+          <lay-form class="form-wp" :model="pageParams" mode="inline" size="sm">
+            <lay-form-item label="盘口" prop="exchange">
+              <lay-select v-model="pageParams.exchange" :show-search="true" allowClear>
+                <lay-select-option v-for="item of rkExchanges" :value="item" :label="item" />
+              </lay-select>
+            </lay-form-item>
+            <div class="form-button-wp">
+              <lay-button @click="getPageInfo()">搜索</lay-button>
+            </div>
+          </lay-form>
+        </div>
+        <div>
+          <lay-table :page="tablePage" size="sm" :columns="columns" resize :data-source="dataShowSource" :loading="pageConfig.loading" @change="handleCurrentChange" @sortChange="handleSortChange">
+            <template v-slot:operator="{ row }">
+              <div>
+                <TableButton text="查看MSV" @click="toJump(row)" />
+              </div>
+            </template>
+          </lay-table>
+        </div>
+      </lay-loading>
+    </template>
+  </lay-card>
+</template>
+
+<script lang="ts" setup name="IndicatorSymbolRank">
+import { ref, reactive } from "vue";
+import { useRouter } from "vue-router";
+import TableButton from "@/components/TableButton.vue";
+import { get_exchange_rank, get_symbols_rank } from "@/api";
+
+const router = useRouter();
+
+interface PageConfig {
+  loading: boolean;
+}
+
+let pageConfig: PageConfig = reactive({
+  loading: false,
+});
+
+interface FormItem {
+  exchange?: string;
+}
+const pageParams: FormItem = reactive({ exchange: "" });
+
+interface TablePage {
+  current: number;
+  limit: number;
+  total: number;
+}
+const tablePage: TablePage = reactive({ current: 1, limit: 20, total: 0, limits: [20, 50, 100, 200, 500] });
+const columns = ref([
+  { title: "币对", width: "110", key: "symbol", ellipsisTooltip: true },
+  { title: "最大Abs(波动率)", key: "msv_abs_max" },
+  { title: "平均Abs(波动率)", key: "msv_abs_avg" },
+  { title: "Sum(Abs(波动率))", key: "msv_abs_total" },
+  { title: "有效波动次数", key: "effective_count" },
+  { title: "平均行情推动量", key: "liquidity_avg" },
+  { title: "Sum(预期利润)", key: "epr_total" },
+  { title: "波动分数", width: "80", key: "msv_score", ellipsisTooltip: true },
+  { title: "交易量分数", width: "100", key: "liquidity_score" },
+  { title: "交易频次分数", width: "100", key: "frequency_score" },
+  { title: "总评分", width: "80", key: "score", sort: "desc", ellipsisTooltip: true },
+  { title: "开仓值", width: "90", key: "coverted_open_base", ellipsisTooltip: true },
+  { title: "操作", width: "90",key: "operator", customSlot: "operator" },
+]);
+let dataSource = ref<any>([]);
+let dataShowSource = ref<any>([]);
+let dataSortSource = ref<any>([]);
+let sortInfo = ref<any>({});
+
+let rkExchanges = ref<any>([]);
+
+const getRkExchanges = () => {
+  const params = {};
+  pageConfig.loading = true;
+  get_exchange_rank(params, (data: any) => {
+    pageConfig.loading = false;
+    if (data.code == 200) {
+      rkExchanges.value = data.data;
+    }
+  });
+};
+getRkExchanges();
+
+// 请求交易所列表
+const getPageInfo = () => {
+  tablePage.current = 1;
+  tablePage.total = 0;
+  dataSource.value = [];
+  const params = {
+    exchange: pageParams.exchange,
+  };
+  pageConfig.loading = true;
+  get_symbols_rank(params, (data: any) => {
+    pageConfig.loading = false;
+    if (data.code == 200) {
+      tablePage.total = data.data.length;
+      dataSource.value = data.data;
+      handleSortChange(sortInfo.value.key, sortInfo.value.sort);
+    }
+  });
+};
+
+const toJump = (value: any) => {
+  router.push({ path: "/indicator/msv", query: { symbol: value.symbol, exchange: pageParams.exchange, minute_time_range: 50 } });
+};
+
+// 分页设置
+const handleCurrentChange = (val: any) => {
+  dataShowSource.value = [...dataSortSource.value.slice((val.current - 1) * val.limit, val.current * val.limit)];
+};
+
+// 排序
+const handleSortChange = (key: any, sort: any) => {
+  sortInfo.value = { key, sort };
+  if (!sort) {
+    dataSortSource.value = [...dataSource.value];
+    dataShowSource.value = [...dataSource.value.slice((tablePage.current - 1) * tablePage.limit, tablePage.current * tablePage.limit)];
+    return;
+  }
+  dataSortSource.value = [...dataSource.value].sort((a: any, b: any) => {
+    let maxA = -9999999;
+    let maxB = -9999999;
+    Object.values(a[key]).map((item) => (maxA = Number(item) > maxA ? Number(item) : maxA));
+    Object.values(b[key]).map((item) => (maxB = Number(item) > maxB ? Number(item) : maxB));
+    return maxA - maxB;
+  });
+  if (sort == "desc") dataSortSource.value.reverse();
+  dataShowSource.value = [...dataSortSource.value.slice((tablePage.current - 1) * tablePage.limit, tablePage.current * tablePage.limit)];
+};
+</script>
+
+<style lang="scss" scoped>
+.custom-form-layout {
+  .custom-card-checkbox,
+  .custom-checkbox {
+    display: inline-flex;
+    align-items: center;
+    margin-bottom: 16px;
+    padding-right: 20px;
+    .label {
+      display: flex;
+      padding-right: 15px;
+    }
+    .checkbox-group {
+      display: flex;
+      .checkbox-wp {
+        display: flex;
+        align-items: center;
+        margin-right: 10px;
+        line-height: 38px;
+        :deep(.layui-checkbox-label) {
+          padding: 0;
+        }
+        :deep(.layui-form-radio) {
+          margin-top: 0;
+        }
+        :deep(.layui-checkcard) {
+          padding: 0 10px;
+          width: auto;
+          margin: 0 10px 0 0;
+          .layui-checkcard-content {
+            padding: 0;
+          }
+        }
+        .checkbox-input {
+          width: 40px;
+        }
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+  .custom-card-checkbox {
+    .checkbox-wp {
+      padding: 0 20px;
+      border: 1px solid #d9d9d9;
+    }
+  }
+}
+</style>