新版仿ok交易所-后端
1
zj
2025-09-30 0c389d73cc79a0027cf779721c6bf184b12f5d86
1
5 files modified
182 ■■■■■ changed files
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java 3 ●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/exchange/dto/ExchangeSymbolDto.java 25 ●●●●● patch | view | raw | blame | history
trading-order-common/src/main/java/com/yami/trading/common/util/UTCDateUtils.java 12 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java 11 ●●●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java 131 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
@@ -1,5 +1,6 @@
package com.yami.trading.api.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yami.trading.api.dto.ChannelBlockchainDto;
import com.yami.trading.api.model.GetChannelBlockchainModel;
@@ -275,7 +276,7 @@
        }
        List<WalletExtend> walletExtends = null;
        log.info(list_symbol.toString() + "=============");
        if (StringUtils.isNotEmpty(partyId)) {
        if (StringUtils.isNotEmpty(partyId) && CollectionUtil.isNotEmpty(list_symbol)) {
            walletExtends = this.walletService.findExtend(partyId, list_symbol);
        }
        if (null == walletExtends) {
trading-order-bean/src/main/java/com/yami/trading/bean/exchange/dto/ExchangeSymbolDto.java
@@ -1,5 +1,7 @@
package com.yami.trading.bean.exchange.dto;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -20,13 +22,34 @@
    private  double positionVolume;//持仓数
    private  double price;  //成本
    private  double currentPrice;//现价
    /**
     * "open":买入 "close":卖出
     */
    private String offset;
    private  double profitLoss=0;  //总盈亏
    /**
     * 状态。submitted 已提交,canceled 已撤销, created 委托完成
     */
    private String state = "submitted";
    /**
     * 平仓时间戳
     */
    private Long closeTimeTs;
    private double toDayProfitLoss=0; //今日盈亏
    private  double profitLossPercentage; //总盈亏百分比
    private  double toDayProfitLossPercentage; //今日盈亏百分比
    /**
     * 累计盈亏
     */
    private double profitTotal;
    /**
     * 当日盈亏(结算)
     */
    private double todayProfit;
}
trading-order-common/src/main/java/com/yami/trading/common/util/UTCDateUtils.java
@@ -7,9 +7,7 @@
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.*;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
@@ -189,5 +187,11 @@
        long endTimestamp = endDate.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        return new Tuple(startTimestamp,endTimestamp);
    }
    public static boolean isTimestampFromToday(long timestamp, ZoneId zoneId) {
        Instant instant = Instant.ofEpochSecond(timestamp);
        LocalDate timestampDate = instant.atZone(zoneId).toLocalDate();
        LocalDate today = LocalDate.now();
        return timestampDate.isEqual(today);
    }
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java
@@ -1,6 +1,7 @@
package com.yami.trading.huobi.data.internal;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.common.config.RequestDataHelper;
@@ -48,11 +49,13 @@
        // 最近60s内实时价格集合
        List<Realtime> list = DataCache.latestRealTimeMap_60s.get(symbol);
        if (list.size() >= KlineConstant.LATEST_REALTIME_LIST_MAX) {
            list.remove(0);
        if(CollectionUtil.isNotEmpty(list)){
            if (list.size() >= KlineConstant.LATEST_REALTIME_LIST_MAX) {
                list.remove(0);
            }
            list.add(realtime);
            DataCache.latestRealTimeMap_60s.put(symbol, list);
        }
        list.add(realtime);
        DataCache.latestRealTimeMap_60s.put(symbol, list);
        RealtimeQueue.add(realtime);
    }
trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java
@@ -7,6 +7,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.yami.trading.bean.data.domain.Kline;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.bean.exchange.ExchangeApplyOrder;
import com.yami.trading.bean.exchange.dto.ExchangeApplyOrderDto;
@@ -40,6 +41,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
@@ -169,16 +171,12 @@
    @Override
    public List<ExchangeSymbolDto> getETFListByUserId(String userId, String type) {
        List<String> symbols = itemService.findByType(type).stream().map(Item::getSymbol).collect(Collectors.toList());
        symbols.add("-1");
        log.info(JSONUtil.toJsonStr(symbols));
        LambdaQueryWrapper<ExchangeApplyOrder> lambdaQueryWrapper = Wrappers.<ExchangeApplyOrder>query().lambda();
        lambdaQueryWrapper.eq(ExchangeApplyOrder::getPartyId, userId);
        lambdaQueryWrapper.in(ExchangeApplyOrder::getSymbol, symbols);
        lambdaQueryWrapper.notIn(ExchangeApplyOrder::getOffset, ExchangeApplyOrder.OFFSET_CLOSE);
//        lambdaQueryWrapper.notIn(ExchangeApplyOrder::getOrderPriceType, "opponent");
        lambdaQueryWrapper.eq(ExchangeApplyOrder::getState, ExchangeApplyOrder.STATE_CREATED);
        lambdaQueryWrapper.eq(ExchangeApplyOrder::getState, ExchangeApplyOrder.STATE_SUBMITTED);
        lambdaQueryWrapper.orderByDesc(ExchangeApplyOrder::getCreateTime);
        List<ExchangeApplyOrder> list = list(lambdaQueryWrapper);
        return getDataList(list);
@@ -203,7 +201,6 @@
    }
    public List<ExchangeSymbolDto> getDataList(List<ExchangeApplyOrder> dbList) {
        List<ExchangeSymbolDto> result = new ArrayList<>();
        Map<String, List<ExchangeSymbolDto>> map = new HashMap<>();
        for (ExchangeApplyOrder order : dbList) {
@@ -211,70 +208,106 @@
            if (exchangeSymbolDtos == null) {
                exchangeSymbolDtos = new ArrayList<>();
            }
//            Realtime realtime = new Realtime();
//            realtime.setClose(new BigDecimal(99));
//            realtime.setOpen(new BigDecimal(100));
//            ExchangeSymbolDto exchangeSymbolDto = new ExchangeSymbolDto();
//            exchangeSymbolDto.setVolume(order.getVolume());
//            exchangeSymbolDto.setName("test");
//            exchangeSymbolDto.setOpenPrice(realtime.getOpen().doubleValue());
//            exchangeSymbolDto.setCurrentPrice(realtime.getClose().doubleValue());
//            exchangeSymbolDto.setPrice(order.getClosePrice());
//            exchangeSymbolDtos.add(exchangeSymbolDto);
//            map.put(order.getSymbol(), exchangeSymbolDtos);
            List<Realtime> symbolList = dataService.realtime(order.getSymbol());
            if (!CollectionUtil.isEmpty(symbolList)) {
                Realtime realtime = symbolList.get(0);
                ExchangeSymbolDto exchangeSymbolDto = new ExchangeSymbolDto();
                exchangeSymbolDto.setVolume(order.getVolume());
                exchangeSymbolDto.setVolume(order.getVolume() != 0 ? order.getVolume() : order.getSymbolValue());
                exchangeSymbolDto.setName(realtime.getName());
                exchangeSymbolDto.setOpenPrice(realtime.getOpen().doubleValue());
                exchangeSymbolDto.setOpenPrice(order.getPrice());
                exchangeSymbolDto.setCurrentPrice(realtime.getClose().doubleValue());
                exchangeSymbolDto.setPrice(order.getClosePrice());
                exchangeSymbolDto.setOffset(order.getOffset());
                exchangeSymbolDto.setState(order.getState());
                exchangeSymbolDto.setCloseTimeTs(order.getCreateTimeTs());
                exchangeSymbolDtos.add(exchangeSymbolDto);
                map.put(order.getSymbol(), exchangeSymbolDtos);
            }
        }
        for (String key : map.keySet()) {
            List<ExchangeSymbolDto> list = map.get(key);
            Item item = itemService.findBySymbol(key);
            double volume = 0; //可用
            double cost = 0.0;
            double costValue = 0.0;//总价值
            double marketValue = 0; //市值
            double currentPrice = 0; //当前价格
            double profitLoss = 0; //总盈亏
            double toDayProfitLoss = 0; //今日总盈亏
            double openPrice = 0;
            double profitLoss = 0; //浮盈
            double toDayProfitLoss = 0; //今日盈亏(浮动)
            double todayProfit = 0; //今日盈亏(结算)
            double profitTotal = 0; //累计盈亏
            double openPrice = 0;//开仓价格
            String name = "";
            for (ExchangeSymbolDto dto : list) {
                volume += dto.getVolume();
            BigDecimal price = BigDecimal.ZERO;//成本价
            List<ExchangeSymbolDto> sort = list.stream().sorted(Comparator.comparing(ExchangeSymbolDto::getCloseTimeTs)).collect(Collectors.toList());
            for (ExchangeSymbolDto dto : sort) {
                name = dto.getName();
                cost += (dto.getVolume() * dto.getPrice());
                currentPrice = dto.getCurrentPrice();
                openPrice = dto.getOpenPrice();
                marketValue += (dto.getCurrentPrice() * dto.getVolume());
                openPrice = dto.getPrice();
                //成本价值
                double cost = dto.getVolume() * dto.getPrice();
                if (dto.getOffset().equals(ExchangeApplyOrder.OFFSET_CLOSE)) {
                    volume -= dto.getVolume();
                    if (ExchangeApplyOrder.STATE_CREATED.equalsIgnoreCase(dto.getState())) {
                        profitTotal += dto.getVolume() * (dto.getPrice() - price.doubleValue());
                        if (dto.getCloseTimeTs() != null && UTCDateUtils.isTimestampFromToday(dto.getCloseTimeTs(), ZoneId.systemDefault())) {
                            todayProfit += dto.getVolume() * (dto.getPrice() - price.doubleValue());
                        }
                        costValue -= (dto.getVolume() * dto.getPrice());
                        marketValue -= (dto.getCurrentPrice() * dto.getVolume());
                    }
                    if (volume == 0) {
                        price = BigDecimal.ZERO;
                    }
                } else {
                    volume += dto.getVolume();
                    if (volume != 0) {
                        price = price.multiply(BigDecimal.valueOf(volume - dto.getVolume()));
                        price = price.add(BigDecimal.valueOf(cost));
                        price = price.divide(BigDecimal.valueOf(volume), item.getDecimals(), RoundingMode.FLOOR);
                    } else {
                        price = BigDecimal.ZERO;
                    }
                    costValue += (dto.getVolume() * dto.getPrice());
                    marketValue += (dto.getCurrentPrice() * dto.getVolume());
                    //当日浮动盈亏
                    List<Kline> kline = dataService.kline(key, Kline.PERIOD_1DAY);
                    kline = kline.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
                    double diff = 0.0;
                    if (CollectionUtil.isNotEmpty(kline)) {
                        Kline day = kline.get(0);
                        Long ts = day.getTs() / 1000;
                        Long timeTs = dto.getCloseTimeTs();
                        if (timeTs > ts) {
                            diff = currentPrice - openPrice;
                        } else {
                            diff = currentPrice - day.getClose().doubleValue();
                        }
                    }
                    toDayProfitLoss += diff * dto.getVolume();
                }
            }
            double price = 0;
            if (volume == 0) {
                price = 0;
            } else {
                price = cost / volume;
            if (volume > 0) {
                //总浮动盈亏
                profitLoss = marketValue - costValue;
                ExchangeSymbolDto exchangeSymbolDto = new ExchangeSymbolDto();
                exchangeSymbolDto.setVolume(new BigDecimal(volume).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setPositionVolume(new BigDecimal(volume).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setPrice(price.setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setName(name);
                exchangeSymbolDto.setSymbol(key);
                exchangeSymbolDto.setToDayProfitLoss(new BigDecimal(toDayProfitLoss).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setToDayProfitLossPercentage(calculateProfitPercentage(openPrice, currentPrice));
                exchangeSymbolDto.setCurrentPrice(new BigDecimal(currentPrice).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setOpenPrice(new BigDecimal(openPrice).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setMarketValue(new BigDecimal(marketValue).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setProfitLoss(new BigDecimal(profitLoss).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setProfitLossPercentage(calculateProfitPercentage(price.doubleValue(), currentPrice));
                exchangeSymbolDto.setProfitTotal(new BigDecimal(profitTotal).setScale(4, RoundingMode.HALF_UP).doubleValue());
                exchangeSymbolDto.setTodayProfit(todayProfit);
                result.add(exchangeSymbolDto);
            }
            toDayProfitLoss = (marketValue - (openPrice * volume));
            profitLoss = marketValue - cost;
            ExchangeSymbolDto exchangeSymbolDto = new ExchangeSymbolDto();
            exchangeSymbolDto.setVolume(new BigDecimal(volume).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setPositionVolume(new BigDecimal(volume).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setPrice(new BigDecimal(price).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setName(name);
            exchangeSymbolDto.setSymbol(key);
            exchangeSymbolDto.setToDayProfitLoss(new BigDecimal(toDayProfitLoss).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setToDayProfitLossPercentage(calculateProfitPercentage(openPrice, currentPrice));
            exchangeSymbolDto.setCurrentPrice(new BigDecimal(currentPrice).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setOpenPrice(new BigDecimal(openPrice).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setMarketValue(new BigDecimal(marketValue).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setProfitLoss(new BigDecimal(profitLoss).setScale(2, RoundingMode.HALF_UP).doubleValue());
            exchangeSymbolDto.setProfitLossPercentage(calculateProfitPercentage(price, currentPrice));
            result.add(exchangeSymbolDto);
        }
        return result;
    }