소스 검색

添加套利资金曲线

DESKTOP-NE65RNK\Citrus_limon 1 년 전
부모
커밋
9bdd78543a
3개의 변경된 파일324개의 추가작업 그리고 0개의 파일을 삭제
  1. 7 0
      src/api/index.ts
  2. 6 0
      src/router/routes.ts
  3. 311 0
      src/views/statistic/balance_arbitrage/index.vue

+ 7 - 0
src/api/index.ts

@@ -494,6 +494,13 @@ export const get_exchange_balance = (params: any, callback: any) => {
   });
 };
 
+// 资金曲线-套利
+export const get_arbitrage_balance = (params: any, callback: any) => {
+  return http.request("/api/remaining/capitalNingBo", "get", params).then((data) => {
+    if (data) callback && callback(data);
+  });
+};
+
 // 利润分析查询
 export const get_exchange_pair_profit = (params: any, callback: any) => {
   return http.request("/api/profitAnalysis/getExchangePairProfitPage", "get", params).then((data) => {

+ 6 - 0
src/router/routes.ts

@@ -94,6 +94,12 @@ const routes: Array<RouteRecordRaw> = [
         component: () => import("@/views/statistic/balance_user/index.vue"),
         meta: { title: "资金曲线-用户", keepAlive: true },
       },
+      {
+        path: "/statistic/balance_arbitrage",
+        name: "StatisticBalanceArbitrage",
+        component: () => import("@/views/statistic/balance_arbitrage/index.vue"),
+        meta: { title: "资金曲线-套利", keepAlive: true },
+      },
       {
         path: "/statistic/profit_analysis",
         name: "StatisticProfitAnalysis",

+ 311 - 0
src/views/statistic/balance_arbitrage/index.vue

@@ -0,0 +1,311 @@
+<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="rangeTime">
+              <lay-date-picker v-model="pageParams.rangeTime" range type="datetime" :placeholder="['开始日期', '结束日期']" />
+            </lay-form-item>
+            <div class="form-button-wp">
+              <lay-button @click="getUserBalanceData()">查询</lay-button>
+            </div>
+            <lay-form-item>
+              <lay-button-group>
+                <lay-button type="default" @click="handleRangeTime(1)">本日</lay-button>
+                <lay-button type="default" @click="handleRangeTime(2)">本周</lay-button>
+                <lay-button type="default" @click="handleRangeTime(3)">本月</lay-button>
+                <lay-button type="default" @click="handleRangeTime(4)">上月</lay-button>
+              </lay-button-group>
+            </lay-form-item>
+            <lay-form-item>
+              <lay-button-group>
+                <lay-button type="default" @click="initChart(balanceData, 1)">按收益率</lay-button>
+                <lay-button type="default" @click="initChart(balanceData, 2)">按收益</lay-button>
+                <lay-button type="default" @click="initChart(balanceData, 3)">按资金</lay-button>
+              </lay-button-group>
+            </lay-form-item>
+          </lay-form>
+        </div>
+        <div>
+          <div class="chart" ref="balanceChartRef"></div>
+        </div>
+      </lay-loading>
+    </template>
+  </lay-card>
+</template>
+
+<script lang="ts" setup name="StatisticBalanceArbitrage">
+import { ref, reactive, onUnmounted, shallowRef } from "vue";
+import * as echarts from "echarts";
+import dayjs from "dayjs";
+import isoWeek from "dayjs/plugin/isoWeek";
+import Decimal from "decimal.js";
+import { get_arbitrage_balance } from "@/api";
+
+dayjs.extend(isoWeek);
+
+const balanceChartRef = ref();
+interface PageConfig {
+  loading: boolean;
+}
+
+interface FormItem {
+  rangeTime: Array<string>;
+}
+
+let pageConfig: PageConfig = reactive({
+  loading: false,
+});
+
+const pageParams: FormItem = reactive({ rangeTime: [dayjs().subtract(24, "hour").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")] });
+
+let balanceChart = shallowRef();
+let balanceData = ref();
+let earningsRateData = ref<Array<any>>([]);
+let earningsData = ref<Array<any>>([]);
+let totalBalanceData = ref<Array<any>>([]);
+
+const getUserBalanceData = () => {
+  balanceData.value = [];
+  earningsRateData.value = [];
+  earningsData.value = [];
+  totalBalanceData.value = [];
+  const params = {
+    startTime: +dayjs(pageParams.rangeTime[0]),
+    endTime: +dayjs(pageParams.rangeTime[1]),
+  };
+  pageConfig.loading = true;
+  get_arbitrage_balance(params, async (data: any) => {
+    pageConfig.loading = false;
+    if (data.code == 200) {
+      balanceData.value = data.data;
+      await handleBalanceData(data.data);
+      initChart(balanceData.value, 1);
+    }
+  });
+};
+getUserBalanceData();
+
+const handleEarningsData = (data: any) => {
+  let transferBalance = new Decimal(0);
+  let earningsList = data.map((item: any, index: any) => {
+    if (index == 0) return 0;
+    if (item.label !== 0) transferBalance = transferBalance.add(item.changeU);
+    return new Decimal(item.afterU || 0).minus(data[0].afterU).minus(transferBalance).toNumber();
+  });
+  return earningsList;
+};
+const handleEarningsRateData = (data: any) => {
+  let transferBalance = data[0].afterU;
+  let transferEarningsRate: any = 0;
+  let lastEarningsRate: any = 0;
+  let earningsList = data.map((item: any, index: any) => {
+    if (index == 0) return 0;
+    if (item.label !== 0) {
+      transferBalance = item.afterU;
+      transferEarningsRate = lastEarningsRate;
+      return transferEarningsRate
+    };
+    let earningsRate = new Decimal(item.afterU || 0).minus(transferBalance).div(transferBalance).mul(100).add(transferEarningsRate).toNumber();
+    lastEarningsRate = earningsRate
+    return earningsRate;
+  });
+  return earningsList;
+};
+const handleTotalBalanceData = (data: any) => {
+  return data.map((item: any) => item.afterU);
+};
+
+const handleBalanceData = (data: any) => {
+  return new Promise((resolve: any) => {
+    // 过滤无效数据
+    balanceData.value = { ...data, userList: data.botList.filter((item: any) => item.balance.length > 0) };
+    balanceData.value.botList.map((item: any) => {
+      let earningList: any = handleEarningsData(item.balance);
+      let earningRateList: any = handleEarningsRateData(item.balance);
+      let totalList: any = handleTotalBalanceData(item.balance);
+      earningsData.value.push({ name: item.name, type: "line", stack: item.name, data: earningList });
+      earningsRateData.value.push({ name: item.name, type: "line", stack: item.name, data: earningRateList });
+      totalBalanceData.value.push({ name: item.name, type: "line", stack: item.name, data: totalList });
+    });
+    resolve(true);
+  });
+};
+
+const handleRangeTime = (type: number) => {
+  const currentTime = +dayjs();
+  const diffTimestamp = +dayjs(currentTime).hour(10).minute(0).second(0).millisecond(0) - currentTime;
+  let timestamp = diffTimestamp <= 0 ? currentTime : currentTime - 1000 * 60 * 60 * 10;
+
+  switch (type) {
+    case 1:
+      pageParams.rangeTime = [`${dayjs(timestamp).hour(10).minute(0).second(0).millisecond(0)}`, `${dayjs()}`];
+      break;
+    case 2:
+      pageParams.rangeTime = [`${dayjs(timestamp).isoWeekday(1).hour(10).minute(0).second(0).millisecond(0)}`, `${dayjs()}`];
+      break;
+    case 3:
+      pageParams.rangeTime = [`${dayjs(timestamp).startOf("month").hour(10).minute(0).second(0).millisecond(0)}`, `${dayjs()}`];
+      break;
+    case 4:
+      let upMonthTime = +dayjs(timestamp).startOf("month") - 1;
+      pageParams.rangeTime = [`${dayjs(upMonthTime).startOf("month").hour(10).minute(0).second(0).millisecond(0)}`, `${dayjs().startOf("month").hour(10).minute(0).second(0).millisecond(0)}`];
+      break;
+  }
+  getUserBalanceData();
+};
+
+const initChart = (data: any, type: number) => {
+  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.timeList.map((item: any) => dayjs(item * 1).format("MM-DD HH:mm"));
+  const legendData = data.userList.map((item: any) => item.name);
+  if (type == 1) {
+    const earningsRateOption = {
+      tooltip: {
+        trigger: "axis",
+        formatter: (value: any) => {
+          const axisLabel = `${value[0].axisValueLabel}`;
+          const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data.toFixed(2)}%`);
+          return `${axisLabel}<br/>${info.join("<br/>")}`;
+        },
+      },
+      toolbox: {
+        feature: {
+          dataZoom: {},
+          brush: {
+            type: ["rect", "clear"],
+          },
+        },
+      },
+      legend: {
+        data: legendData,
+        top: "bottom",
+      },
+      xAxis: {
+        type: "category",
+        data: xData,
+      },
+      yAxis: {
+        type: "value",
+        min: "dataMin",
+        axisLabel: {
+          formatter: (value: any) => {
+            return `${value.toFixed(2)}%`;
+          },
+        },
+      },
+      series: earningsRateData.value,
+    };
+    balanceChart.value.setOption(earningsRateOption);
+  }
+  if (type == 2) {
+    const earningsOption = {
+      tooltip: {
+        trigger: "axis",
+        formatter: (value: any) => {
+          const axisLabel = `${value[0].axisValueLabel}`;
+          const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data}`);
+          return `${axisLabel}<br/>${info.join("<br/>")}`;
+        },
+      },
+      toolbox: {
+        feature: {
+          dataZoom: {},
+          brush: {
+            type: ["rect", "clear"],
+          },
+        },
+      },
+      legend: {
+        data: legendData,
+        top: "bottom",
+      },
+      xAxis: {
+        type: "category",
+        data: xData,
+      },
+      yAxis: {
+        type: "value",
+        min: "dataMin",
+      },
+      series: earningsData.value,
+    };
+    balanceChart.value.setOption(earningsOption);
+  }
+  if (type == 3) {
+    const earningsOption = {
+      tooltip: {
+        trigger: "axis",
+        formatter: (value: any) => {
+          const axisLabel = `${value[0].axisValueLabel}`;
+          const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data}`);
+          return `${axisLabel}<br/>${info.join("<br/>")}`;
+        },
+      },
+      toolbox: {
+        feature: {
+          dataZoom: {},
+          brush: {
+            type: ["rect", "clear"],
+          },
+        },
+      },
+      legend: {
+        data: legendData,
+        top: "bottom",
+      },
+      xAxis: {
+        type: "category",
+        data: xData,
+      },
+      yAxis: {
+        type: "value",
+        min: "dataMin",
+      },
+      series: totalBalanceData.value,
+    };
+    balanceChart.value.setOption(earningsOption);
+  }
+};
+
+onUnmounted(() => {
+  window.removeEventListener("resize", () => balanceChart.value.resize());
+});
+</script>
+
+<style lang="scss" scoped>
+.custom-card {
+  min-width: 256px;
+  .form-button-wp {
+    margin-right: 60px;
+  }
+}
+.chart {
+  padding-top: 20px;
+  min-height: 500px;
+}
+.robot-info-header {
+  background-color: white;
+  padding: 16px 24px;
+  margin-bottom: 20px;
+  .robot-name {
+    font-size: 14px;
+    font-weight: bold;
+  }
+  .robot-status {
+    span {
+      font-size: 12px;
+      padding-left: 4px;
+    }
+  }
+}
+</style>