1
zj
2025-05-08 4130970dd61791e0a5cb0771a9b707084f1ed464
src/main/java/com/nq/utils/task/stock/StockTask.java
@@ -1,26 +1,35 @@
package com.nq.utils.task.stock;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.nq.common.ServerResponse;
import com.nq.dao.StockMapper;
import com.nq.dao.UserMapper;
import com.nq.dao.UserPendingorderMapper;
import com.nq.dao.UserPositionMapper;
import com.nq.enums.EConfigKey;
import com.nq.enums.EStockType;
import com.nq.pojo.DataStockBean;
import com.nq.pojo.ReponseBase;
import com.nq.pojo.Stock;
import com.nq.pojo.UserPosition;
import com.nq.enums.EUserAssets;
import com.nq.pojo.*;
import com.nq.pojo.reponse.kResponse;
import com.nq.service.IMandatoryLiquidationService;
import com.nq.service.IStockService;
import com.nq.service.IUserPositionService;
import com.nq.service.*;
import com.nq.service.impl.StockServiceImpl;
import com.nq.service.impl.UserServiceImpl;
import com.nq.utils.ConverterUtil;
import com.nq.utils.KeyUtils;
import com.nq.utils.UserPointUtil;
import com.nq.utils.http.HttpClientRequest;
import com.nq.utils.redis.RedisKeyConstant;
import com.nq.utils.redis.RedisKeyUtil;
import com.nq.utils.redis.RedisShardedPoolUtils;
import com.nq.utils.stock.GeneratePosition;
import com.nq.vo.position.PositionProfitVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,9 +38,12 @@
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
@@ -55,12 +67,19 @@
    @Autowired
    UserPositionMapper userPositionMapper;
    private final Lock stockConstraintLock = new ReentrantLock();
    @Autowired
    private UserPendingorderService userPendingorderService;
    @Autowired
    IMandatoryLiquidationService mandatoryLiquidationService;
    @Autowired
    IUserAssetsServices iUserAssetsServices;
    @Autowired
    IStockConfigServices iStockConfigServices;
    @Autowired
    IPriceServices priceServices;
    @Autowired
    UserMapper userMapper;
    private static final Logger log = LoggerFactory.getLogger(StockTask.class);
@@ -88,6 +107,226 @@
            }
        }
    }
    /**
     * 挂单
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void pendingOrder() {
        ReentrantLock lock = new ReentrantLock();
        if (lock.tryLock()) { // 尝试获取锁
            try {
                pending();
            }catch (Exception e){
                e.printStackTrace();
                log.error("买入挂单定时任务报错:",e.getMessage());
            }
            finally {
                lock.unlock();  // 释放锁
            }
        } else {
            // 如果锁不可用,可以选择不执行或打印日志等
            System.out.println("买入挂单定时任务  任务正在执行,跳过本次执行。");
        }
    }
    /**
     * 挂单平仓
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void closeOrder() {
        ReentrantLock lock = new ReentrantLock();
        if (lock.tryLock()) { // 尝试获取锁
            try {
                closeOutOrder();
            }catch (Exception e){
                e.printStackTrace();
                log.error("平仓挂单定时任务报错:",e.getMessage());
            }
            finally {
                lock.unlock();  // 释放锁
            }
        } else {
            // 如果锁不可用,可以选择不执行或打印日志等
            System.out.println("平仓挂单定时任务  任务正在执行,跳过本次执行。");
        }
    }
    public void closeOutOrder() {
        List<UserPendingorder> list = userPendingorderService.list(new LambdaQueryWrapper<>(UserPendingorder.class)
                .eq(UserPendingorder::getPositionType, 1)
                .eq(UserPendingorder::getHangingOrderType,2));
        if(CollectionUtil.isNotEmpty(list)){
            list.forEach(f->{
                //获取当前价格
                //股票类型 现价 数据源的处理
                BigDecimal nowPrice = BigDecimal.ZERO;
                if(f.getStockType().equals("ST")){
                    nowPrice = priceServices.getNowPrice(f.getStockCode());
                }else{
                    nowPrice = new BigDecimal(RedisShardedPoolUtils.get(RedisKeyConstant.getRedisKey(f.getStockName())));
                }
                if((f.getOrderDirection().equals("买涨") && nowPrice.compareTo(f.getSellOrderPrice()) >= 0) || (f.getOrderDirection().equals("买跌") && nowPrice.compareTo(f.getSellOrderPrice()) <= 0)){
                    closeStockTransferPositions(f);
                }
            });
        }
    }
    private void closeStockTransferPositions(UserPendingorder f) {
        UserPosition userPosition = userPositionMapper.selectOne(new LambdaQueryWrapper<>(UserPosition.class)
                .eq(UserPosition::getPositionSn, f.getPositionSn())
                .eq(UserPosition::getUserId, f.getUserId())
        );
        BigDecimal siitteBuyFee = new BigDecimal(iStockConfigServices.queryByKey(EConfigKey.SELL_HANDLING_CHARGE.getCode()).getCValue());
        //部分平仓
        if(f.getOrderNum() < userPosition.getOrderNum()){
            //拆分订单
            UserPosition position = ConverterUtil.convert(userPosition,UserPosition.class);
            position.setId(null);
            position.setPositionSn(KeyUtils.getUniqueKey());
            //得到均价
            double buyOrderPrice = position.getOrderTotalPrice().doubleValue() / position.getOrderNum().doubleValue() * position.getOrderLever();
            position.setOrderNum(userPosition.getOrderNum()-f.getOrderNum());
            BigDecimal positionBuyAmt = new BigDecimal(buyOrderPrice).multiply(new BigDecimal(position.getOrderNum())).divide(new BigDecimal(position.getOrderLever()));
            position.setOrderTotalPrice(positionBuyAmt);
            position.setBuyOrderPrice(new BigDecimal(buyOrderPrice));
            position.setBuyOrderId(GeneratePosition.getPositionId());
            //修改拆分订单手续费
            BigDecimal BuyFee = new BigDecimal(iStockConfigServices.queryByKey(EConfigKey.BUY_HANDLING_CHARGE.getCode()).getCValue());
            BigDecimal buyPrice = position.getBuyOrderPrice().multiply(new BigDecimal(position.getOrderNum()));
            BigDecimal xsPrice = buyPrice.multiply(BuyFee);
            position.setOrderFee(xsPrice);
            userPositionMapper.insert(position);
            //得到均价
            double orderPrice = userPosition.getOrderTotalPrice().doubleValue() / userPosition.getOrderNum().doubleValue() * position.getOrderLever();
            //修改原订单
            userPosition.setOrderNum(f.getOrderNum());
            BigDecimal buyAmt = new BigDecimal(orderPrice).multiply(new BigDecimal(userPosition.getOrderNum())).divide(new BigDecimal(userPosition.getOrderLever()));
            userPosition.setOrderTotalPrice(buyAmt);
            userPosition.setOrderFee(userPosition.getOrderFee().subtract(position.getOrderFee()));
            userPositionMapper.updateById(userPosition);
        }
        getObjectServerResponse(userPosition, f.getSellOrderPrice(), siitteBuyFee, f.getStockType());
        f.setPositionType(2);
        userPendingorderService.updateById(f);
    }
    public void getObjectServerResponse( UserPosition userPosition, BigDecimal nowPrice, BigDecimal siitteBuyFee, String stockType) {
        userPosition.setSellOrderId(GeneratePosition.getPositionId());
        userPosition.setSellOrderPrice(nowPrice);
        userPosition.setSellOrderTime(new Date());
        BigDecimal sellOrderTotel = nowPrice.multiply(new BigDecimal(userPosition.getOrderNum()));
        BigDecimal xsPrice = sellOrderTotel.multiply(siitteBuyFee);
        userPosition.setOrderFee(userPosition.getOrderFee().add(xsPrice));
        userPositionMapper.updateById(userPosition);
        iUserAssetsServices.availablebalanceChange(stockType,
                userPosition.getUserId(),
                EUserAssets.CLOSE_POSITION_RETURN_SECURITY_DEPOSIT,
                userPosition.getOrderTotalPrice(), "", "");
        iUserAssetsServices.availablebalanceChange(stockType,
                userPosition.getUserId(), EUserAssets.HANDLING_CHARGE,
                xsPrice, "", "");
        PositionProfitVO profitVO = UserPointUtil.getPositionProfitVO(userPosition,
                priceServices.getNowPrice(userPosition.getStockCode()));
        iUserAssetsServices.availablebalanceChange(stockType,
                userPosition.getUserId(), EUserAssets.CLOSE_POSITION,
                profitVO.getAllProfitAndLose(), "", "");
    }
    public void pending(){
        List<UserPendingorder> list = userPendingorderService.list(new LambdaQueryWrapper<>(UserPendingorder.class)
                .eq(UserPendingorder::getPositionType, 1)
                .eq(UserPendingorder::getHangingOrderType,1));
        if(CollectionUtil.isNotEmpty(list)){
            list.forEach(f->{
                if(f.getStockGid().equals("ST")){
                    //获取当前价格
                    //股票类型 现价 数据源的处理
                    BigDecimal nowPrice = priceServices.getNowPrice(f.getStockCode());
                    if((f.getOrderDirection().equals("买涨") && f.getBuyOrderPrice().compareTo(nowPrice) >= 0) || (f.getOrderDirection().equals("买跌") && f.getBuyOrderPrice().compareTo(nowPrice) <= 0)){
                        stockTransferPositions(f);
                    }
                }else{
                    String price = RedisShardedPoolUtils.get(RedisKeyConstant.getRedisKey(f.getStockName()));
                    if((f.getOrderDirection().equals("买涨") && f.getBuyOrderPrice().compareTo(new BigDecimal(price)) >= 0) || (f.getOrderDirection().equals("买跌") && f.getBuyOrderPrice().compareTo(new BigDecimal(price)) <= 0)){
                        hjTransferPositions(f);
                    }
                }
            });
        }
    }
    public void hjTransferPositions(UserPendingorder userPendingorder){
        UserPosition position = userPositionMapper.selectOne(new LambdaQueryWrapper<>(UserPosition.class)
                .eq(UserPosition::getUserId, userPendingorder.getUserId())
                .eq(UserPosition::getStockCode, userPendingorder.getStockCode())
                .isNull(UserPosition::getSellOrderId)
        );
        User user = userMapper.selectById(userPendingorder.getUserId());
        BigDecimal siteSettingBuyFee = new BigDecimal(iStockConfigServices.queryByKey(EConfigKey.BUY_HANDLING_CHARGE.getCode()).getCValue()) ;
        BigDecimal orderFree = siteSettingBuyFee.multiply(userPendingorder.getOrderTotalPrice());
        UserPosition userPosition = ConverterUtil.convert(userPendingorder, UserPosition.class);
        if(ObjectUtil.isEmpty(position)){
            userPosition.setPositionType(user.getAccountType());
            userPosition.setId(null);
            userPendingorder.setPositionType(0);
            userPendingorderService.updateById(userPendingorder);
            userPositionMapper.insert(userPosition);
            iUserAssetsServices.availablebalanceChange("USD", user.getId(), EUserAssets.HANDLING_CHARGE, orderFree, "", "");
        }else{
            position.setOrderNum(position.getOrderNum()+userPosition.getOrderNum());
            position.setOrderTotalPrice(position.getOrderTotalPrice().add(userPosition.getOrderTotalPrice()));
            position.setOrderFee(position.getOrderFee().add(orderFree));
            position.setBuyOrderPrice(position.getBuyOrderPrice());
            position.setAllProfitAndLose(position.getAllProfitAndLose().add(orderFree));
            userPositionMapper.updateById(position);
            userPendingorder.setPositionType(0);
            userPendingorderService.updateById(userPendingorder);
            iUserAssetsServices.availablebalanceChange("USD", user.getId(), EUserAssets.HANDLING_CHARGE, orderFree, "", "");
        }
    }
    public void stockTransferPositions(UserPendingorder userPendingorder){
        UserPosition position = userPositionMapper.selectOne(new LambdaQueryWrapper<>(UserPosition.class)
                .eq(UserPosition::getUserId, userPendingorder.getUserId())
                .eq(UserPosition::getStockCode, userPendingorder.getStockCode())
                .isNull(UserPosition::getSellOrderId)
        );
        // 手续费率
        BigDecimal siteSettingBuyFee = new BigDecimal(iStockConfigServices.queryByKey(EConfigKey.BUY_HANDLING_CHARGE.getCode()).getCValue()) ;
        BigDecimal orderFree = siteSettingBuyFee.multiply(userPendingorder.getOrderTotalPrice());
        User user = userMapper.selectById(userPendingorder.getUserId());
        UserPosition userPosition = ConverterUtil.convert(userPendingorder, UserPosition.class);
        if(ObjectUtil.isEmpty(position)){
            userPosition.setPositionType(user.getAccountType());
            userPosition.setId(null);
            userPendingorder.setPositionType(0);
            userPendingorderService.updateById(userPendingorder);
            userPositionMapper.insert(userPosition);
            //挂单成功扣除手续费
            iUserAssetsServices.availablebalanceChange("ST", user.getId(), EUserAssets.HANDLING_CHARGE, orderFree, "", "");
        }else{
            position.setOrderNum(position.getOrderNum()+userPosition.getOrderNum());
            position.setOrderTotalPrice(position.getOrderTotalPrice().add(userPosition.getOrderTotalPrice()));
            position.setOrderFee(position.getOrderFee().add(orderFree));
            double divide = position.getOrderTotalPrice().doubleValue() / position.getOrderNum();
            position.setBuyOrderPrice(new BigDecimal(divide*position.getOrderLever()));
            position.setAllProfitAndLose(position.getAllProfitAndLose().add(orderFree));
            userPositionMapper.updateById(position);
            userPendingorder.setPositionType(0);
            userPendingorderService.updateById(userPendingorder);
            //挂单成功扣除手续费
            iUserAssetsServices.availablebalanceChange("ST", user.getId(), EUserAssets.HANDLING_CHARGE, orderFree, "", "");
        }
    }
    //最新价格url
    private static final String PRICE_URL = "https://quote.alltick.io/quote-b-api/trade-tick?token=794ea65dc03c5af582cddec476fbb0d7-c-app&query=";
    //k线url
@@ -140,7 +379,7 @@
        if (lock.tryLock()) { // 尝试获取锁
            try {
                gold();
                Thread.sleep(1000);
                Thread.sleep(2000);
                getKDate();
            } finally {
                lock.unlock();  // 释放锁
@@ -224,7 +463,7 @@
                RedisShardedPoolUtils.set("k_gold_"+entry.getKey(), gold);
            }
            Thread.sleep(1000);
            Thread.sleep(2000);
            String c = getResp(K_URL+getKQueryData(entry.getValue(),"USOIL"));
            if(StringUtils.isNotEmpty(c)){
                if(entry.getKey().equals("d")) {
@@ -232,7 +471,7 @@
                }
                RedisShardedPoolUtils.set("k_crude_oil_"+entry.getKey(), c);
            }
            Thread.sleep(1000);
            Thread.sleep(2000);
        }
    }
@@ -264,12 +503,13 @@
            kData.setVo(item.getTurnover());
            kDataList.add(kData);
        }
        DecimalFormat decimalFormat = new DecimalFormat("#.00");
        double oneC = Double.valueOf(kDataList.get(kDataList.size() - 1).getC());
        double twoC = Double.valueOf(kDataList.get(kDataList.size() - 2).getC());
        String h = String.valueOf(decimalFormat.format(((oneC - twoC) / oneC * 100)));
        RedisShardedPoolUtils.set(key+"_H",h);
        RedisShardedPoolUtils.set(key+"_H",h);
        String h = String.valueOf(((oneC - twoC) / oneC * 100));
        BigDecimal bd = new BigDecimal(h);
        bd = bd.setScale(2, RoundingMode.DOWN);  // RoundingMode.DOWN 表示截断而非四舍五入
        RedisShardedPoolUtils.set(key+"_H",bd.toString());
        RedisShardedPoolUtils.set(key+"_H",bd.toString());
    }
    public String getResp(String url){