1
zj
2025-04-30 4bb0b890438349a7cfd7ab2dc30999346a5acf58
src/main/java/com/nq/utils/task/stock/StockTask.java
@@ -1,26 +1,57 @@
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.QueryWrapper;
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.dao.*;
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.enums.EUserAssets;
import com.nq.pojo.*;
import com.nq.service.IMandatoryLiquidationService;
import com.nq.service.IStockService;
import com.nq.pojo.reponse.kResponse;
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.stock.BuyAndSellUtils;
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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
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.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@Component
@@ -30,89 +61,531 @@
    @Autowired
    StockMapper stockMapper;
    @Autowired
    IUserPositionService userPositionService;
    @Autowired
    UserPositionMapper userPositionMapper;
    @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);
    public void time(boolean am, boolean pm) {
        am = false;
        pm = false;
        try {
            am = BuyAndSellUtils.isTransTime("9:29", "11:31");
            pm = BuyAndSellUtils.isTransTime("12:59", "15:00");
        } catch (Exception e) {
            log.error("= {}", e);
        }
        log.info("am = {}  pm = {}", Boolean.valueOf(am), Boolean.valueOf(pm));
    }
    private final AtomicBoolean syncINStockData = new AtomicBoolean(false);
    private final Lock syncINStockDataLock = new ReentrantLock();
    /**
     * 同步系统所需要的股票
     * */
    @Scheduled(cron = "0 0/3 *  * * ?")
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void syncINStockData() {
//        loadAllStock(EStockType.US);
        loadAllStock(EStockType.HG);
    }
    /**
     * 同步美国股票
     * */
    @Scheduled(cron = "0 0/30 * * * ?")
    public  void loadStockCompanies(){
        loadAllCompanies();
    }
    /**
     * 加载公司信息
     * */
    public  void loadAllCompanies(){
        List<Stock>  list =   stockMapper.findStockList();
        for (int i = 0; i <list.size() ; i++) {
            Stock stock = list.get(i);
            EStockType eStockType = EStockType.getEStockTypeByCode(stock.getStockType());
            String result = HttpClientRequest.doGet(eStockType.stockUrl+"companies?pid=+"+stock.getStockCode()+"+country_id="+eStockType.getContryId()+"&size=1&page=1&key="+eStockType.stockKey);
        if (syncINStockData.get()) { // 判断任务是否在处理中
            return;
        }
        if (syncINStockDataLock.tryLock()) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(result);
                JSONObject companiesInfo = jsonObject.getJSONArray("data").getJSONObject(0);
                RedisKeyUtil.setCacheCompanies(stock,new Gson().toJson(companiesInfo));
            }catch (Exception e){
                log.info("");
                syncINStockData.set(true); // 设置处理中标识为true
                loadAllStock(EStockType.ST);
            } finally {
                syncINStockDataLock.unlock();
                syncINStockData.set(false); // 设置处理中标识为false
            }
        }
    }
    /**
     * 挂单
     */
    @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
    private static final String K_URL = "https://quote.alltick.io/quote-b-api/kline?token=794ea65dc03c5af582cddec476fbb0d7-c-app&query=";
    public String getPriceData() {
        // 创建查询数据
        JSONObject data = new JSONObject();
        // 用于存储符号的列表
        JSONArray symbolList = new JSONArray();
        // 需要查询的符号列表(按你的要求,这里符号从 ["857.HK", "UNH.US"] 开始)
        String[] symbols = {"GOLD", "USOIL"};
        // 遍历符号列表,构建 JSON 对象
        for (String symbol : symbols) {
            JSONObject symbolObject = new JSONObject();
            symbolObject.put("code", symbol);
            symbolList.put(symbolObject);
        }
        // 将 symbol_list 放入 data 对象中
        data.put("symbol_list", symbolList);
        // 创建查询请求对象
        JSONObject query = new JSONObject();
        query.put("trace", generateTraceCode()); // 假设 generateTraceCode() 是生成唯一追踪代码的方法
        query.put("data", data);
        // 返回构建的查询对象
        return buildUrlWithQuery(query);
    }
    // 生成唯一追踪码
    public static String generateTraceCode() {
        // 获取当前时间戳
        long timestamp = System.currentTimeMillis();
        // 生成唯一的 UUID
        String uuid = UUID.randomUUID().toString();
        // 组合时间戳和 UUID,保证唯一性
        return uuid + "-" + timestamp;
    }
    @Scheduled(cron = "0/2 * * * * ?")  // 每6秒执行一次
    public void sync() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        if (lock.tryLock()) { // 尝试获取锁
            try {
                gold();
                Thread.sleep(2000);
                getKDate();
            } finally {
                lock.unlock();  // 释放锁
            }
        } else {
            // 如果锁不可用,可以选择不执行或打印日志等
            System.out.println("任务正在执行,跳过本次执行。");
        }
    }
    public void gold() {
        try {
            String url = PRICE_URL+getPriceData();
            URL obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
            con.setRequestMethod("GET");
            int responseCode = con.getResponseCode();
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            if(responseCode == 200){
                // 创建 ObjectMapper 对象
                ObjectMapper objectMapper = new ObjectMapper();
                // 解析 JSON 字符串
                JsonNode rootNode = objectMapper.readTree(response.toString());
                // 获取 "data" 节点下的 "tick_list" 数组
                JsonNode tickList = rootNode.path("data").path("tick_list");
                // 遍历 tick_list 数组并提取 code 和 price
                for (JsonNode tick : tickList) {
                    String code = tick.path("code").asText().equals("GOLD") ? "XAUUSD" : tick.path("code").asText();
                    String price = tick.path("price").asText();
                    RedisShardedPoolUtils.set(RedisKeyConstant.getRedisKey(code), price);
                }
            }else{
                log.info("黄金原油获实时价格定时任务------没有接收到数据:"+response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static String buildUrlWithQuery(JSONObject jsonObject) {
        try {
            // 将 JSON 对象转换为字符串
            String jsonString = jsonObject.toString();
            // 使用 URLEncoder 编码 JSON 字符串
            String encodedJson = URLEncoder.encode(jsonString, "UTF-8");
            return encodedJson;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
    public void getKDate() throws InterruptedException {
        // 创建Map对象
        Map<String, Integer> map = new HashMap<>();
        // 写死键值对
        map.put("d", 8);
        map.put("w", 9);
        map.put("m", 10);
        map.put("1", 1);
        map.put("5", 2);
        map.put("30", 4);
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            String gold = getResp(K_URL + getKQueryData(entry.getValue(), "XAUUSD"));
            if(StringUtils.isNotEmpty(gold)){
                if(entry.getKey().equals("d")){
                    priceLimit(gold,"XAUUSD");
                }
                RedisShardedPoolUtils.set("k_gold_"+entry.getKey(), gold);
            }
            Thread.sleep(2000);
            String c = getResp(K_URL+getKQueryData(entry.getValue(),"USOIL"));
            if(StringUtils.isNotEmpty(c)){
                if(entry.getKey().equals("d")) {
                    priceLimit(c, "USOIL");
                }
                RedisShardedPoolUtils.set("k_crude_oil_"+entry.getKey(), c);
            }
            Thread.sleep(2000);
        }
    }
    @lombok.Data
    class kData {
        long t;
        String c;
        String o;
        String h;
        String l;
        String v;
        String vo;
    }
    public void priceLimit(String data,String key){
        List<kData> kDataList = new ArrayList<>();
        // 使用 Gson 解析 JSON 字符串
        Gson gson = new Gson();
        kResponse kResponse = gson.fromJson(data, kResponse.class);
        // 打印 kline_list 的内容
        for (kResponse.KlineData item : kResponse.getData().getKlineList()) {
            kData kData = new kData();
            kData.setT(item.getTimestamp());
            kData.setC(item.getClose_price());
            kData.setO(item.getOpen_price());
            kData.setH(item.getHigh_price());
            kData.setL(item.getLow_price());
            kData.setV(item.getVolume());
            kData.setVo(item.getTurnover());
            kDataList.add(kData);
        }
        double oneC = Double.valueOf(kDataList.get(kDataList.size() - 1).getC());
        double twoC = Double.valueOf(kDataList.get(kDataList.size() - 2).getC());
        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){
        try {
            URL obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
            con.setRequestMethod("GET");
            int responseCode = con.getResponseCode();
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            if(responseCode == 200){
                return response.toString();
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("k线请求错误!", e.getMessage());
        }
        return null;
    }
    //k线请求组装数据
    public String getKQueryData(Integer k_data,String code){
        JSONObject queryData = new JSONObject();
        queryData.put("trace", generateTraceCode());
        JSONObject data = new JSONObject();
        data.put("code", code);//产品code
        /**
         * k线类型
         * 1、1是1分钟K,2是5分钟K,3是15分钟K,4是30分钟K,5是小时K,6是2小时K(股票不支持2小时),7是4小时K(股票不支持4小时),8是日K,9是周K,10是月K (注:股票不支持2小时K、4小时K)
         * 2、最短的k线只支持1分钟
         * 3、查询昨日收盘价,kline_type 传8
         */
        data.put("kline_type", k_data);
        /**
         * 从指定时间往前查询K线
         * 1、传0表示从当前最新的交易日往前查k线
         * 2、指定时间请传时间戳,传时间戳表示从该时间戳往前查k线
         * 3、只有外汇贵金属加密货币支持传时间戳,股票类的code不支持
         */
        data.put("kline_timestamp_end", 0);
        /**
         * 1、表示查询多少根K线,每次最大请求1000根,可根据时间戳循环往前请求
         * 2、通过该字段可查询昨日收盘价,kline_type 传8,query_kline_num传2,返回2根k线数据中,时间戳较小的数据是昨日收盘价
         */
        data.put("query_kline_num", 200);
        /*
            复权类型,对于股票类的code才有效,例如:0:除权,1:前复权,目前仅支持0
         */
        data.put("adjust_type", 0);
        queryData.put("data", data);
        return buildUrlWithQuery(queryData);
    }
    /**
     * 加载所有股票数据
     * */
    public  void  loadAllStock(EStockType eStockType){
        log.info("同步股票 数据 {}",eStockType.getCode());
     */
    public void loadAllStock(EStockType eStockType) {
        log.info("同步股票 数据 {}", eStockType.getCode());
        List<DataStockBean> list = new ArrayList<>();
        int totleStock = 1;
        int page =0;
        int page = 0;
        try {
            while (totleStock>list.size()){
                try{
                    String result = HttpClientRequest.doGet(eStockType.stockUrl+"list?country_id="+eStockType.getContryId()+"&size=1000&page="+page+"&key="+eStockType.stockKey);
                    ReponseBase reponseBase  = new Gson().fromJson(result,ReponseBase.class);
            while (totleStock > list.size()) {
                try {
                    String result = HttpClientRequest.doGet(eStockType.stockUrl + "list?country_id=" + eStockType.getContryId() + "&size=1000&page=" + page + "&key=" + eStockType.stockKey);
                    ReponseBase reponseBase = new Gson().fromJson(result, ReponseBase.class);
                    list.addAll(reponseBase.getData());
                    page++;
                    totleStock = reponseBase.getTotal();
                }catch (Exception e){
                } catch (Exception e) {
                    e.printStackTrace();
                    break;
                }
@@ -124,63 +597,68 @@
                    stock.setStockCode(o.getId());
                    stock.setStockName(o.getName());
                    stock.setStockType(eStockType.getCode());
                    if(o.getType() == null){
                    if (o.getType() == null) {
                        stock.setStockGid(eStockType.getCode());
                    }else{
                    } else {
                        stock.setStockGid(o.getType());
                    }
                    if(eStockType.getCode().equals("US")){
                        stock.setStockSpell(o.getSymbol());
                    }else{
                        stock.setStockSpell(o.getTicker());
                    }
                    stock.setStockSpell(o.getSymbol());
                    stock.setIsLock(0);
                    stock.setIsShow(0);
                    stock.setDataBase(0);
                    stock.setAddTime(new Date());
                    stockMapper.insert1(stock);
                } else {
                    stock.setStockCode(o.getId());
                    stock.setStockName(o.getName());
                    stock.setStockType(eStockType.getCode());
                    if (o.getType() == null) {
                        stock.setStockGid(eStockType.getCode());
                    } else {
                        stock.setStockGid(o.getType());
                    }
                    stock.setStockSpell(o.getSymbol());
                    stock.setIsLock(0);
                    stock.setIsShow(0);
                    stock.setDataBase(0);
                    stock.setAddTime(new Date());
                    stockMapper.updateById(stock);
                }
                RedisKeyUtil.setCaCheKeyBaseStock(eStockType,o);
                RedisKeyUtil.setCaCheKeyBaseStock(eStockType, o);
            }
            log.info("同步股票 数据 成功 {}  总共同步数据 {}",eStockType.getCode(),list.size());
            log.info("同步股票 数据 成功 {}  总共同步数据 {}", eStockType.getCode(), list.size());
        } catch (
                Exception e) {
            log.error("同步出错", e);
        }
    }
    private final AtomicBoolean stockConstraint = new AtomicBoolean(false);
    /***
     * 每3分钟同步一次数据源到数据库
     *
    /**
     * 强制平仓
     */
    @Scheduled(cron = "0/3 * * * * ?")
    public  void  sysnInstockData(){
        QueryWrapper<Stock>  queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("stock_type",EStockType.SZHB.getCode());
        List<Stock> stockList = stockMapper.selectList(queryWrapper);
        for (int i = 0; i < stockList.size(); i++) {
            try {
                String hdataString =  HttpClientRequest.doGet(EStockType.SZHB.stockUrl+"market/detail?symbol="+stockList.get(i).getStockCode());
                HBData hbData = new Gson().fromJson(hdataString,HBData.class);
                StockRealTimeBean stockRealTimeBean = new StockRealTimeBean();
                stockRealTimeBean.setLast(hbData.getTick().getClose()+"");
                stockRealTimeBean.setHigh(hbData.getTick().getHigh()+"");
                stockRealTimeBean.setPid(stockList.get(i).getStockCode());
                stockRealTimeBean.setLow(hbData.getTick().getLow()+"");
                stockRealTimeBean.setBid(hbData.getTick().getOpen()+"");
                stockRealTimeBean.setLast_close("0.00");
                 BigDecimal sss =  (new BigDecimal(hbData.getTick().getClose()).subtract(new BigDecimal(hbData.getTick().getOpen())));
                       sss = sss.divide(new BigDecimal(hbData.getTick().getOpen()),BigDecimal.ROUND_CEILING);
                stockRealTimeBean.setPcp(sss.setScale(2,BigDecimal.ROUND_UP).toString());
                mandatoryLiquidationService.RealTimeDataProcess(EStockType.SZHB,stockRealTimeBean);
            }catch (Exception e){
            }
        }
    }
//    @Scheduled(cron = "0/1 * * * * ?")
//    public void stockConstraint() {
//        if (stockConstraint.get()) { // 判断任务是否在处理中
//            return;
//        }
//        if (stockConstraintLock.tryLock()) {
//            try {
//                stockConstraint.set(true); // 设置处理中标识为true
//                List<UserPosition> userPositions = userPositionMapper.selectList(new LambdaQueryWrapper<UserPosition>().isNull(UserPosition::getSellOrderId));
//                if (CollectionUtils.isNotEmpty(userPositions)) {
//                    userPositionService.stockConstraint(userPositions);
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//                log.error("强制平仓任务错误:" + e.getMessage());
//            } finally {
//                stockConstraintLock.unlock();
//                stockConstraint.set(false); // 设置处理中标识为false
//            }
//        } else {
//            log.info("强制平仓任务--------->上次任务还未执行完成,本次任务忽略");
//        }
//    }
}