| | |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import com.nq.Repository.ExchangeRateRepository; |
| | | import com.nq.common.ResponseCode; |
| | | import com.nq.common.ServerResponse; |
| | | import com.nq.dao.StockAiMapper; |
| | | import com.nq.dao.StockAiOrderMapper; |
| | | import com.nq.dao.StockAiOrderPositionMapper; |
| | | import com.nq.enums.*; |
| | | import com.nq.pojo.*; |
| | | import com.nq.service.*; |
| | | import com.nq.vo.stock.ai.StockAiOrderTypeVO; |
| | | import com.nq.vo.stock.ai.StockAiOrderVO; |
| | | import com.nq.vo.stock.ai.StockAiVO; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import java.math.BigDecimal; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | @Service("iStockAiService") |
| | | public class StockAiServiceImpl implements IStockAiService { |
| | | private static final Logger log = LoggerFactory.getLogger(StockAiServiceImpl.class); |
| | | private final ConcurrentHashMap<Long, Object> locks = new ConcurrentHashMap<>(); |
| | | |
| | | @Autowired |
| | | StockAiMapper stockAiMapper; |
| | | @Autowired |
| | | StockAiOrderMapper stockAiOrderMapper; |
| | | @Autowired |
| | | StockAiOrderPositionMapper stockAiOrderPositionMapper; |
| | | @Autowired |
| | | ISiteProductService iSiteProductService; |
| | | @Autowired |
| | | IUserService iUserService; |
| | | @Autowired |
| | | IUserAssetsServices iUserAssetsServices; |
| | | @Autowired |
| | | ExchangeRateRepository exchangeRateRepository; |
| | | |
| | | /** |
| | | * 获取上架ai产品 |
| | |
| | | public ServerResponse getStockAiList(Integer pageNum, Integer pageSize) { |
| | | try { |
| | | PageHelper.startPage(pageNum, pageSize); |
| | | List<StockAI> stockAiList = stockAiMapper.selectList(new QueryWrapper<StockAI>().eq("status", EStockAIStatus.online.getValue())); |
| | | List<StockAI> stockAiList = stockAiMapper.selectList(new QueryWrapper<StockAI>() |
| | | .eq("status", EStockAIStatus.online.getValue())); |
| | | // 获取分页信息 |
| | | PageInfo<StockAI> pageInfo = new PageInfo<>(stockAiList); |
| | | return ServerResponse.createBySuccess(pageInfo); |
| | |
| | | * @return |
| | | */ |
| | | @Override |
| | | @Transactional |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public ServerResponse buyStockAi(Long id, BigDecimal buyNum, HttpServletRequest request) { |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | if (user == null ){ |
| | | return ServerResponse.createBySuccessMsg("請先登錄"); |
| | | return ServerResponse.createByErrorCodeMsg(ResponseCode.NEED_LOGIN.getCode(),"请先登录", request); |
| | | } |
| | | synchronized (user.getId()){ |
| | | Object lock = locks.computeIfAbsent(Long.valueOf(user.getId()), k -> new Object()); |
| | | synchronized (lock){ |
| | | SiteProduct siteProduct = iSiteProductService.getProductSetting(); |
| | | if (siteProduct.getRealNameDisplay() && user.getIsActive() != 2) { |
| | | return ServerResponse.createByErrorMsg("订单失败,请先实名认证", request); |
| | |
| | | if (stockAI == null) { |
| | | return ServerResponse.createByErrorMsg("订单失败,AI股票不存在", request); |
| | | } |
| | | |
| | | if (!stockAI.getStatus().equals(EStockAIStatus.online.getValue())) { |
| | | return ServerResponse.createByErrorMsg("订单失败,AI股票已下架", request); |
| | | } |
| | | if(buyNum.compareTo(stockAI.getMinPrice()) < 0){ |
| | | return ServerResponse.createByErrorMsg("最低购买数量" + stockAI.getMinPrice(), request); |
| | | } |
| | | //获取用户账户 |
| | | UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId(EStockType.MX.getCode(), user.getId()); |
| | | BigDecimal finalBuyNum = buyNum; //购买金额 |
| | | /*BigDecimal finalBuyNum = buyNum; //购买金额 |
| | | //如果不是墨西哥币需要转换金额 |
| | | if (!stockAI.getStockType().equals(EStockType.US.getCode())) { |
| | | if (!stockAI.getStockType().equals(EStockType.MX.getCode())) { |
| | | EStockType stockType = EStockType.getEStockTypeByCode(stockAI.getStockType()); |
| | | |
| | | ExchangeRate exchangeRate = exchangeRateRepository.findExchangeRateByCurrencyAndConversionCurrency(stockType.getSymbol(), EStockType.MX.getSymbol()) |
| | | .orElse(null); |
| | | if (exchangeRate == null) { |
| | |
| | | } |
| | | //转换为墨西哥币 |
| | | buyNum = iUserAssetsServices.exchangeAmountByRate(buyNum, exchangeRate.getRata()); |
| | | } |
| | | }*/ |
| | | if(buyNum.compareTo(userAssets.getAvailableBalance()) > 0){ |
| | | return ServerResponse.createByErrorMsg("可用余额不足" + userAssets.getAvailableBalance(), request); |
| | | } |
| | |
| | | if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){ |
| | | return ServerResponse.createByErrorMsg("请先缴清待补资金", request); |
| | | } |
| | | |
| | | iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), user.getId(), EUserAssets.BUY_AI, buyNum); |
| | | StockAIOrder stockAIOrder = new StockAIOrder(); |
| | | stockAIOrder.setUserId(user.getId()); |
| | | stockAIOrder.setStockAiId(id); |
| | | stockAIOrder.setStockAiId(id.intValue()); |
| | | stockAIOrder.setBuyDate(new Date()); |
| | | stockAIOrder.setBuyAmount(finalBuyNum); |
| | | stockAIOrder.setRemainAmount(finalBuyNum); |
| | | stockAIOrder.setBuyAmount(buyNum); |
| | | stockAIOrder.setRemainAmount(buyNum); |
| | | stockAIOrder.setRealEarning(BigDecimal.valueOf(0)); |
| | | stockAIOrder.setStatus(EStockAIOrderStatus.wait.getStatus()); //等待审核 |
| | | stockAiOrderMapper.insert(stockAIOrder); |
| | | iUserAssetsServices.aiAvailableBalanceChange(userAssets, EUserAssets.BUY_AI, buyNum); |
| | | return ServerResponse.createBySuccessMsg("下单成功", request); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("StockAiService buyStockAiList error", e); |
| | | log.error("StockAiService buyStockAiList {}", e.getMessage()); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | |
| | | try { |
| | | User user = iUserService.getCurrentUser(request); |
| | | if (user == null ){ |
| | | return ServerResponse.createBySuccessMsg("請先登錄"); |
| | | return ServerResponse.createByErrorCodeMsg(ResponseCode.NEED_LOGIN.getCode(),"请先登录", request); |
| | | } |
| | | |
| | | PageHelper.startPage(pageNum, pageSize); |
| | | List<StockAIOrder> stockAIOrders = stockAiOrderMapper.selectList(new QueryWrapper<StockAIOrder>() |
| | | .eq("user_id", user.getId()) |
| | | .eq(status != null && !status.isEmpty(), "status", status)); |
| | | List<StockAiOrderTypeVO> stockAIOrders = stockAiOrderMapper.getStockAiOrderList(user.getId(), status); |
| | | // 获取分页信息 |
| | | PageInfo<StockAIOrder> pageInfo = new PageInfo<>(stockAIOrders); |
| | | PageInfo<StockAiOrderTypeVO> pageInfo = new PageInfo<>(stockAIOrders); |
| | | return ServerResponse.createBySuccess(pageInfo); |
| | | } catch (Exception e) { |
| | | log.error("StockAiService getStockAiOrderList error", e); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | @Override |
| | | public ServerResponse getAdminStockAiList(Integer pageNum, Integer pageSize, String stockType, String status, String name) { |
| | | try { |
| | | PageHelper.startPage(pageNum, pageSize); |
| | | List<StockAiVO> stockAiList = stockAiMapper.getStockAiList(stockType, status, name); |
| | | // 获取分页信息 |
| | | PageInfo<StockAiVO> pageInfo = new PageInfo<>(stockAiList); |
| | | |
| | | if (!pageInfo.getList().isEmpty()) { |
| | | List<StockAiVO> newStockAiList = pageInfo.getList(); |
| | | pageInfo.getList().forEach(stockAiVO -> { |
| | | EStockType eStockType = EStockType.getEStockTypeByCode(stockAiVO.getStockType()); |
| | | stockAiVO.setStockTypeName(eStockType.getSymbol1()); |
| | | stockAiVO.setSymbol(stockType); |
| | | }); |
| | | pageInfo.setList(newStockAiList); |
| | | } |
| | | return ServerResponse.createBySuccess(pageInfo); |
| | | } catch (Exception ex) { |
| | | log.error("StockAiService getAdminStockAiList error", ex); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | /** |
| | | * 新增或修改 |
| | | * @param model |
| | | * @return |
| | | */ |
| | | @Override |
| | | public ServerResponse editStockAi(StockAI model) { |
| | | try { |
| | | if (model == null) { |
| | | return ServerResponse.createByErrorMsg("editStockAi model is null"); |
| | | } |
| | | if (model.getStockType().isEmpty() || model.getStockName().isEmpty() || model.getMinPrice() == null |
| | | || model.getSuccessRate() == null || model.getExpectedEarning() == null || model.getStatus().isEmpty()) { |
| | | return ServerResponse.createByErrorMsg("请完善必填信息"); |
| | | } |
| | | if (!model.getStockType().equals(EStockType.US.getCode()) && !model.getStockType().equals(EStockType.MX.getCode())) { |
| | | return ServerResponse.createByErrorMsg("只能选择美股或墨西哥股"); |
| | | } |
| | | //新增 |
| | | if (model.getId() == null) { |
| | | //查询是否存在 |
| | | StockAI stockAI = stockAiMapper.selectOne(new QueryWrapper<StockAI>().eq("stock_name", model.getStockName())); |
| | | if (stockAI != null) { |
| | | return ServerResponse.createByErrorMsg("当前股票已添加"); |
| | | } |
| | | model.setCreateDate(new Date()); |
| | | stockAiMapper.insert(model); |
| | | } else { //修改 |
| | | stockAiMapper.updateById(model); |
| | | } |
| | | return ServerResponse.createBySuccess("操作成功"); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | log.error(e.getMessage(), e); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | /** |
| | | * 后台查询ai交易订单 |
| | | * @param pageNum |
| | | * @param pageSize |
| | | * @param stockType |
| | | * @param status |
| | | * @param userId |
| | | * @param phone |
| | | * @return |
| | | */ |
| | | @Override |
| | | public ServerResponse getAdminStockAiOrderList(Integer pageNum, Integer pageSize, String stockType, String status, Integer userId, String phone) { |
| | | try { |
| | | PageHelper.startPage(pageNum, pageSize); |
| | | List<StockAiOrderVO> stockAIOrders = stockAiOrderMapper.getAdminStockAiOrderList(stockType, status, userId, phone); |
| | | // 获取分页信息 |
| | | PageInfo<StockAiOrderVO> pageInfo = new PageInfo<>(stockAIOrders); |
| | | |
| | | if (!pageInfo.getList().isEmpty()) { |
| | | List<StockAiOrderVO> newStockAiOrders = pageInfo.getList(); |
| | | newStockAiOrders.forEach(stockAiOrderVO -> { |
| | | EStockType eStockType = EStockType.getEStockTypeByCode(stockAiOrderVO.getStockType()); |
| | | stockAiOrderVO.setStockTypeName(eStockType.getSymbol1()); |
| | | stockAiOrderVO.setSymbol(stockType); |
| | | }); |
| | | pageInfo.setList(newStockAiOrders); |
| | | } |
| | | return ServerResponse.createBySuccess(pageInfo); |
| | | } catch (Exception e) { |
| | | log.error("StockAiService getAdminStockAiOrderList error", e); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | /** |
| | | * 建仓 |
| | | * @param model |
| | | * @return |
| | | */ |
| | | @Override |
| | | public ServerResponse openPosition(StockAIOrderPosition model) { |
| | | try { |
| | | Object lock = locks.computeIfAbsent(Long.valueOf(model.getStockAiOrderId()), k -> new Object()); |
| | | synchronized (lock) { |
| | | StockAIOrder stockAIOrder = stockAiOrderMapper.selectById(model.getStockAiOrderId()); |
| | | if (stockAIOrder == null) { |
| | | return ServerResponse.createByErrorMsg("AI订单不存在"); |
| | | } |
| | | |
| | | if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.passed.getStatus())) { |
| | | return ServerResponse.createByErrorMsg("申请通过状态才能建仓!"); |
| | | } |
| | | //计算剩余金额 |
| | | BigDecimal remainAmount = model.getStockPrice().multiply(BigDecimal.valueOf(model.getStockNum())); |
| | | if (stockAIOrder.getRemainAmount().compareTo(remainAmount) < 0) { |
| | | return ServerResponse.createByErrorMsg("剩余买入金额不足"); |
| | | } |
| | | stockAIOrder.setRemainAmount(stockAIOrder.getRemainAmount().subtract(remainAmount)); |
| | | |
| | | //计算收益 (平仓-建仓)*数量 |
| | | BigDecimal earnings = model.getCoverPrice().subtract(model.getStockPrice()).multiply(BigDecimal.valueOf(model.getStockNum())); |
| | | model.setCreatDate(new Date()); |
| | | model.setEarnings(earnings); |
| | | model.setStatus(0); |
| | | stockAIOrder.setRealEarning(stockAIOrder.getRealEarning().add(earnings)); |
| | | |
| | | //保存 |
| | | stockAiOrderMapper.updateById(stockAIOrder); |
| | | stockAiOrderPositionMapper.insert(model); |
| | | return ServerResponse.createBySuccess("建仓成功"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("StockAiService openPosition error", e); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public ServerResponse orderOperation(Long id, String status) { |
| | | try { |
| | | Object lock = locks.computeIfAbsent(id, k -> new Object()); |
| | | synchronized (lock) { |
| | | StockAIOrder stockAIOrder = stockAiOrderMapper.selectById(id); |
| | | if (stockAIOrder == null) { |
| | | return ServerResponse.createByErrorMsg("AI订单不存在"); |
| | | } |
| | | if (status.equals(EStockAIOrderStatus.passed.getStatus())) { |
| | | //通过 |
| | | if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.wait.getStatus())) { |
| | | return ServerResponse.createByErrorMsg("只能通过待审核订单"); |
| | | } |
| | | } else if (status.equals(EStockAIOrderStatus.notPass.getStatus())) { |
| | | if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.wait.getStatus())) { |
| | | return ServerResponse.createByErrorMsg("只能拒绝待审核订单"); |
| | | } |
| | | //拒绝TODO 归还买入金额 |
| | | StockAI stockAI = stockAiMapper.selectById(stockAIOrder.getStockAiId()); |
| | | //买入金额 |
| | | BigDecimal buyNum = stockAIOrder.getBuyAmount(); |
| | | iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), stockAIOrder.getUserId(), EUserAssets.BUY_AI_REJECT, buyNum); |
| | | } else if (status.equals(EStockAIOrderStatus.finished.getStatus())) { |
| | | if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.passed.getStatus())) { |
| | | return ServerResponse.createByErrorMsg("只能结算申请通过订单"); |
| | | } |
| | | //结算 TODO结算建仓 计算收益 |
| | | /*//所有建仓 |
| | | |
| | | List<StockAIOrderPosition> stockAIOrderPositionList = stockAiOrderPositionMapper |
| | | .selectList(new QueryWrapper<StockAIOrderPosition>() |
| | | .eq("stock_ai_order_id", id)); |
| | | //结算金额 |
| | | BigDecimal amount = stockAIOrder.getBuyAmount(); |
| | | if (!stockAIOrderPositionList.isEmpty()) { |
| | | //总收益 |
| | | BigDecimal earningsSUM = stockAIOrderPositionList.stream() |
| | | .map(StockAIOrderPosition::getEarnings) // 获取 BigDecimal 字段 |
| | | .filter(Objects::nonNull) // 过滤 null 值 |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加 |
| | | amount = amount.add(earningsSUM); |
| | | }*/ |
| | | StockAI stockAI = stockAiMapper.selectById(stockAIOrder.getStockAiId()); |
| | | //结算修改为平仓状态 |
| | | stockAiOrderPositionMapper.updateStatusByOrderId(stockAIOrder.getId(), 1); |
| | | //归还本金 |
| | | iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), stockAIOrder.getUserId(), EUserAssets.AI_SETTLEMENT, stockAIOrder.getBuyAmount()); |
| | | //收益 |
| | | iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), stockAIOrder.getUserId(), EUserAssets.AI_SETTLEMENT_INT, stockAIOrder.getRealEarning()); |
| | | } |
| | | stockAIOrder.setStatus(status); |
| | | stockAIOrder.setAuditDate(new Date()); |
| | | stockAiOrderMapper.updateById(stockAIOrder); |
| | | return ServerResponse.createBySuccess("操作成功"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("StockAiService openPosition error", e); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | } |