package com.yami.trading.api.controller.trader;
|
|
import cn.hutool.core.util.StrUtil;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.yami.trading.bean.contract.domain.ContractOrder;
|
import com.yami.trading.bean.item.domain.Item;
|
import com.yami.trading.bean.model.User;
|
import com.yami.trading.common.domain.BaseEntity;
|
import com.yami.trading.bean.trader.FollowCommissionType;
|
import com.yami.trading.bean.trader.domain.Trader;
|
import com.yami.trading.bean.trader.domain.TraderFollowSetting;
|
import com.yami.trading.bean.trader.domain.TraderFollowUser;
|
import com.yami.trading.bean.trader.domain.TraderFollowUserOrder;
|
import com.yami.trading.bean.trader.domain.TraderInviteLink;
|
import com.yami.trading.common.constants.Constants;
|
import com.yami.trading.common.exception.BusinessException;
|
import com.yami.trading.common.exception.YamiShopBindException;
|
import com.yami.trading.common.util.*;
|
import com.yami.trading.common.web.ResultObject;
|
import com.yami.trading.security.common.util.SecurityUtils;
|
import com.yami.trading.service.contract.ContractOrderService;
|
import com.yami.trading.service.item.ItemService;
|
import com.yami.trading.service.trader.*;
|
import com.yami.trading.service.user.UserService;
|
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.LogFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import javax.servlet.http.HttpServletRequest;
|
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
import java.time.YearMonth;
|
import java.time.ZoneId;
|
import java.time.temporal.ChronoUnit;
|
import java.text.DecimalFormat;
|
import java.text.ParseException;
|
import java.text.SimpleDateFormat;
|
import java.time.Instant;
|
import java.util.*;
|
import java.util.regex.Pattern;
|
|
|
|
/**
|
* 交易员api接口
|
*/
|
@RestController
|
@CrossOrigin
|
@RequestMapping()
|
public class ApiTraderController {
|
/**
|
* 交易员api接口
|
*/
|
private static Log logger = LogFactory.getLog(ApiTraderController.class);
|
|
@Autowired
|
private TraderService traderService;
|
|
@Autowired
|
private TraderUserService traderUserService;
|
|
@Autowired
|
private TraderFollowUserService traderFollowUserService;
|
|
@Autowired
|
private TraderFollowUserOrderService traderFollowUserOrderService;
|
|
@Autowired
|
private TraderOrderService traderOrderService;
|
|
@Autowired
|
private ContractOrderService contractOrderService;
|
|
@Autowired
|
private UserService userService;
|
|
@Autowired
|
private ItemService itemService;
|
|
@Autowired
|
private TraderFollowSettingService traderFollowSettingService;
|
|
@Autowired
|
private TraderInviteLinkService traderInviteLinkService;
|
|
/**
|
* 查询类型 orders 当前委托数 ,hisorders 历史委托数 ,user 跟随数
|
*/
|
// private String type;
|
|
private final String action = "/api/trader!";
|
|
@RequestMapping(action + "list.action")
|
public Object list(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
|
String name = request.getParameter("name");
|
String state = request.getParameter("state");
|
// String orderBy_type = request.getParameter("orderBy_type");
|
String page_no = request.getParameter("page_no");
|
try {
|
if (StringUtils.isNullOrEmpty(page_no)) {
|
page_no = "1";
|
}
|
if (!StringUtils.isInteger(page_no)) {
|
throw new YamiShopBindException("页码不是整数");
|
}
|
if (Integer.valueOf(page_no).intValue() <= 0) {
|
throw new YamiShopBindException("页码不能小于等于0");
|
}
|
Page<Trader> page = new Page<>(1, 1000000);
|
|
data = traderService.getPaged(page, name, state);
|
if (data != null) {
|
for (int i = 0; i < data.size(); i++) {
|
Map<String, Object> map = data.get(i);
|
String partyId = SecurityUtils.getCurrentUserId();
|
Object commissionTypeForRemaining = map.get("follow_commission_type");
|
if (partyId != null) {
|
TraderFollowUser user = this.traderFollowUserService.findByPartyIdAndTrader_partyId(partyId, map.get("partyId").toString());
|
if (user != null) {
|
map.put("follow_state", user.getState());
|
map.put("follow_volume", user.getVolume());
|
map.put("follow_volume_max", user.getVolumeMax());
|
map.put("follow_monthly_remaining_days",
|
computeFollowMonthlyRemainingDays(commissionTypeForRemaining, user));
|
map.remove("partyId");
|
} else {
|
map.put("follow_state", "2");
|
map.put("follow_monthly_remaining_days", null);
|
map.remove("partyId");
|
}
|
|
} else {
|
map.put("follow_state", "2");
|
map.put("follow_monthly_remaining_days", null);
|
map.remove("partyId");
|
}
|
}
|
|
}
|
|
// List<Trader> data = traderService.findAllState_1();
|
|
// resultObject.setData(bulidData(data));
|
resultObject.setData(data);
|
resultObject.setCode("0");
|
} catch (BusinessException e) {
|
resultObject.setCode("1");
|
resultObject.setMsg(e.getMessage());
|
} catch (Exception e) {
|
resultObject.setCode("1");
|
resultObject.setMsg("程序错误");
|
logger.error("error:", e);
|
}
|
|
return resultObject;
|
|
}
|
|
/**
|
* 查询是否是交易员
|
* @param request
|
* @return
|
*/
|
@RequestMapping(action + "istrader.action")
|
public Object istrader(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
try {
|
String id = request.getParameter("id");
|
|
Trader data = null;
|
if (StringUtils.isNotEmpty(id)) {
|
data = traderService.findById(id);
|
} else {
|
String partyId = SecurityUtils.getCurrentUserId();
|
if (StringUtils.isEmptyString(partyId)) {
|
resultObject.setCode("1");
|
resultObject.setMsg("用户未登录");
|
Map<String, Object> empty = new HashMap<>();
|
empty.put("exists", false);
|
empty.put("checked", null);
|
empty.put("can_reapply", false);
|
empty.put("reject_reason", "");
|
empty.put("name", "");
|
empty.put("symbols", "");
|
empty.put("follow_volumn_min", 0d);
|
empty.put("follow_commission_type", FollowCommissionType.LEGACY);
|
empty.put("follow_commission_monthly_amount", "0");
|
empty.put("follow_commission_daily_pct", 0d);
|
empty.put("profit_share_ratio", 0d);
|
empty.put("id", "");
|
empty.put("img", "");
|
empty.put("img_path", "");
|
resultObject.setData(empty);
|
return resultObject;
|
}
|
data = traderService.findByPartyId(partyId);
|
}
|
Map<String, Object> ret = new HashMap<>();
|
ret.put("exists", data != null);
|
ret.put("checked", data == null ? null : data.getChecked());
|
ret.put("can_reapply", data != null && data.getChecked() == -1);
|
ret.put("reject_reason", data != null && data.getChecked() == -1 ? data.getRemarks() : "");
|
ret.put("name", data == null ? "" : data.getName());
|
ret.put("symbols", data == null ? "" : data.getSymbols());
|
ret.put("follow_volumn_min", data == null || data.getFollowVolumnMin() == null ? 0d : data.getFollowVolumnMin().doubleValue());
|
if (data != null) {
|
ret.put("follow_commission_type", FollowCommissionType.normalizeOrLegacy(data.getFollowCommissionType()));
|
ret.put("follow_commission_monthly_amount",
|
data.getFollowCommissionMonthlyAmount() == null ? "0"
|
: data.getFollowCommissionMonthlyAmount().stripTrailingZeros().toPlainString());
|
ret.put("follow_commission_daily_pct", Arith.mul(data.getFollowCommissionDailyPct(), 100));
|
ret.put("profit_share_ratio", Arith.mul(data.getProfitShareRatio(), 100));
|
} else {
|
ret.put("follow_commission_type", FollowCommissionType.LEGACY);
|
ret.put("follow_commission_monthly_amount", "0");
|
ret.put("follow_commission_daily_pct", 0d);
|
ret.put("profit_share_ratio", 0d);
|
}
|
ret.put("id", data == null ? "" : data.getUuid());
|
if (data != null && !StringUtils.isEmptyString(data.getImg())) {
|
ret.put("img", Constants.WEB_URL + "/public/showimg!showImg.action?imagePath=" + data.getImg());
|
ret.put("img_path", data.getImg());
|
} else {
|
ret.put("img", "");
|
ret.put("img_path", "");
|
}
|
resultObject.setData(ret);
|
resultObject.setCode("0");
|
return resultObject;
|
} catch (Exception e) {
|
logger.error("istrader error", e);
|
resultObject.setCode("1");
|
resultObject.setMsg(e.getMessage() != null ? e.getMessage() : "程序错误");
|
Map<String, Object> err = new HashMap<>();
|
err.put("exists", false);
|
err.put("checked", null);
|
err.put("can_reapply", false);
|
err.put("reject_reason", "");
|
err.put("name", "");
|
err.put("symbols", "");
|
err.put("follow_volumn_min", 0d);
|
err.put("follow_commission_type", FollowCommissionType.LEGACY);
|
err.put("follow_commission_monthly_amount", "0");
|
err.put("follow_commission_daily_pct", 0d);
|
err.put("profit_share_ratio", 0d);
|
err.put("id", "");
|
err.put("img", "");
|
err.put("img_path", "");
|
resultObject.setData(err);
|
return resultObject;
|
}
|
}
|
|
/**
|
* 交易员详情(本人或指定 id)。同时注册 {@code /api/trader/get},避免网关对 {@code !} 路径返回 404。
|
*/
|
@RequestMapping(value = { action + "get.action", "/api/trader/get" })
|
public Object get(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
String id = request.getParameter("id");
|
String type = request.getParameter("type");
|
String symbol = request.getParameter("symbol");
|
String page_no = request.getParameter("page_no");
|
try {
|
if (StringUtils.isNullOrEmpty(page_no)) {
|
page_no = "1";
|
}
|
if (!StringUtils.isInteger(page_no)) {
|
throw new YamiShopBindException("页码不是整数");
|
}
|
if (Integer.valueOf(page_no).intValue() <= 0) {
|
throw new YamiShopBindException("页码不能小于等于0");
|
}
|
Page<Trader> page = new Page<>(1, 1000000);
|
Trader data = null;
|
if (StringUtils.isNotEmpty(id)) {
|
data = traderService.findById(id);
|
if (null == data) {
|
resultObject.setCode("1");
|
resultObject.setMsg("交易员不存在");
|
return resultObject;
|
}
|
} else {
|
String partyId = SecurityUtils.getCurrentUserId();
|
if (StringUtils.isEmptyString(partyId)) {
|
resultObject.setCode("1");
|
resultObject.setMsg("用户未登录");
|
return resultObject;
|
}
|
data = traderService.findByPartyId(partyId);
|
if (null == data) {
|
resultObject.setCode("1");
|
/** 未传 id 时按当前登录用户查 T_TRADER;无记录表示从未申请或数据未写入,与「传错 uuid」区分 */
|
resultObject.setMsg("当前账号暂无交易员记录,请先提交申请或确认登录账号是否正确");
|
return resultObject;
|
}
|
}
|
|
Map<String, Object> retData = bulidData(data, type, symbol, page);
|
resultObject.setData(retData);
|
resultObject.setCode("0");
|
} catch (BusinessException e) {
|
resultObject.setCode("1");
|
resultObject.setMsg(e.getMessage());
|
} catch (Exception e) {
|
resultObject.setCode("1");
|
resultObject.setMsg("程序错误");
|
logger.error("error:", e);
|
}
|
|
return resultObject;
|
}
|
|
@RequestMapping(action + "generate.action")
|
public Object generate(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
String profit_share_ratio = request.getParameter("profit_share_ratio");
|
String ids = request.getParameter("ids");
|
String level = request.getParameter("level");
|
|
if(StringUtils.isEmptyString(profit_share_ratio)) {
|
resultObject.setCode("1");
|
resultObject.setMsg("佣金分成比例不能为空");
|
return resultObject;
|
}
|
|
String partyId = SecurityUtils.getCurrentUserId();
|
|
TraderInviteLink traderInviteLink = traderInviteLinkService.findByTraderIdAndStatus(partyId, 1);
|
if(null == traderInviteLink) {
|
traderInviteLink = new TraderInviteLink();
|
String uuid = ApplicationUtil.getCurrentTimeUUID();
|
traderInviteLink.setUuid(uuid);
|
traderInviteLink.setTraderId(partyId);
|
traderInviteLink.setProfitShareRatio(Double.parseDouble(profit_share_ratio));
|
traderInviteLink.setIds(ids);
|
traderInviteLink.setLevel(Integer.parseInt(level));
|
traderInviteLink.setStatus(1);
|
String link = "https://sjiepc.com/syn/#/followUpStrategy/index?type=share&id=" + uuid;
|
traderInviteLink.setLink(link);
|
traderInviteLinkService.save(traderInviteLink);
|
resultObject.setData(link);
|
} else {
|
resultObject.setCode("1");
|
resultObject.setMsg("该用户已生成过邀请链接!");
|
return resultObject;
|
}
|
resultObject.setCode("0");
|
resultObject.setMsg("生成邀请链接成功!");
|
|
return resultObject;
|
}
|
|
@RequestMapping(action + "getInviteLink.action")
|
public Object getInviteLink(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
String partyId = SecurityUtils.getCurrentUserId();
|
|
resultObject.setCode("0");
|
resultObject.setMsg("获取数据成功!");
|
|
TraderInviteLink traderInviteLink = traderInviteLinkService.findByTraderIdAndStatus(partyId, 1);
|
if(null != traderInviteLink) {
|
long remain = getRemainTime(traderInviteLink.getCreateTimeTs());
|
if (remain <= 0) {
|
traderInviteLink.setStatus(0);
|
traderInviteLinkService.update(traderInviteLink);
|
} else {
|
resultObject.setData(traderInviteLink);
|
}
|
}
|
|
return resultObject;
|
}
|
|
@RequestMapping(action + "follow.action")
|
public Object follow(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
String id = request.getParameter("id");
|
String usercode = request.getParameter("usercode");
|
TraderInviteLink traderInviteLink = traderInviteLinkService.selectById(id);
|
|
long createTime = traderInviteLink.getCreateTimeTs();
|
|
long remain = getRemainTime(createTime);
|
|
if(0==traderInviteLink.getStatus() || remain <= 0) { // 链接已失效
|
resultObject.setCode("1");
|
resultObject.setMsg("跟单失败!");
|
return resultObject;
|
}
|
|
User user = userService.findUserByUserCode(usercode);
|
User trader = userService.findByUserId(traderInviteLink.getTraderId());
|
|
TraderFollowUser traderFollowUser = new TraderFollowUser();
|
traderFollowUser.setPartyId(user.getUserId());
|
traderFollowUser.setUserCode(usercode);
|
traderFollowUser.setUsername(user.getUserName());
|
traderFollowUser.setTraderPartyId(trader.getUserId());
|
traderFollowUser.setFollowType("1");
|
traderFollowUser.setState("1");
|
|
traderFollowUserService.save(traderFollowUser);
|
|
resultObject.setCode("0");
|
resultObject.setMsg("跟单成功!");
|
return resultObject;
|
}
|
|
@RequestMapping(action + "expire.action")
|
public Object expire(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
String id = request.getParameter("id");
|
TraderInviteLink traderInviteLink = traderInviteLinkService.selectById(id);
|
long remain = 0L;
|
resultObject.setCode("0");
|
resultObject.setMsg("获取数据成功!");
|
if(0==traderInviteLink.getStatus()) {
|
resultObject.setData(remain);
|
return resultObject;
|
}
|
long createTime = traderInviteLink.getCreateTimeTs();
|
|
remain = getRemainTime(createTime);
|
|
if(remain <= 0) { // 链接已失效
|
traderInviteLink.setStatus(0);
|
remain = 0L;
|
traderInviteLinkService.update(traderInviteLink);
|
}
|
|
resultObject.setData(remain);
|
return resultObject;
|
}
|
|
private long getRemainTime(long createTime) {
|
long remain = 0L;
|
Instant instant = Instant.now();
|
long now = instant.getEpochSecond();
|
remain = 3600 - (now - createTime);
|
return remain;
|
}
|
|
/** 带单品种分隔:分号、逗号(含全角) */
|
private static final Pattern TRADER_SYMBOL_SPLIT = Pattern.compile("[;;,,]+");
|
|
/**
|
* 校验带单品种是否在系统合约品种(Item)中存在;支持多品种(与 T_TRADER.SYMBOLS 约定一致,用分号拼接规范 symbol)。
|
* 匹配顺序:symbol(含缓存/remarks 映射)→ 小写 symbol → 展示名 name(兼容旧数据)。
|
*/
|
private String validateAndNormalizeTraderSymbols(String raw) throws BusinessException {
|
if (StringUtils.isEmptyString(raw)) {
|
throw new BusinessException("请输入带单品种");
|
}
|
String trimmed = raw.trim();
|
String[] tokens = TRADER_SYMBOL_SPLIT.split(trimmed);
|
LinkedHashSet<String> seen = new LinkedHashSet<>();
|
List<String> normalized = new ArrayList<>();
|
for (String token : tokens) {
|
if (token == null) {
|
continue;
|
}
|
String part = token.trim();
|
if (part.isEmpty()) {
|
continue;
|
}
|
Item item = itemService.findBySymbol(part);
|
if (item == null) {
|
item = itemService.findBySymbol(part.toLowerCase(Locale.ROOT));
|
}
|
if (item == null) {
|
item = itemService.lambdaQuery()
|
.eq(Item::getName, part)
|
.eq(BaseEntity::getDelFlag, 0)
|
.last("LIMIT 1")
|
.one();
|
}
|
if (item == null || StringUtils.isEmptyString(item.getSymbol())) {
|
throw new BusinessException("带单品种无效或不支持:" + part);
|
}
|
String canon = item.getSymbol();
|
if (seen.add(canon)) {
|
normalized.add(canon);
|
}
|
}
|
if (normalized.isEmpty()) {
|
throw new BusinessException("请输入带单品种");
|
}
|
return String.join(";", normalized);
|
}
|
|
@RequestMapping(action + "apply.action")
|
public Object apply(HttpServletRequest request) {
|
ResultObject resultObject = new ResultObject();
|
String partyId = SecurityUtils.getCurrentUserId();
|
|
String symbols = request.getParameter("symbols");
|
if (symbols != null) {
|
symbols = symbols.trim();
|
}
|
String name = request.getParameter("name");
|
|
String follow_volumn_min_param = request.getParameter("follow_volumn_min");
|
String state = "1";
|
String img = request.getParameter("img");
|
String remarks = request.getParameter("remarks");
|
|
try {
|
BigDecimal follow_volumn_min = BigDecimal.ZERO;
|
if (!StringUtils.isEmptyString(follow_volumn_min_param)) {
|
try {
|
follow_volumn_min = new BigDecimal(follow_volumn_min_param.trim());
|
} catch (NumberFormatException e) {
|
throw new BusinessException("最小跟单币数量格式不正确");
|
}
|
}
|
if (follow_volumn_min.signum() < 0) {
|
throw new BusinessException("最小跟单币数量不能小于0");
|
}
|
if (StringUtils.isEmptyString(remarks)) {
|
throw new BusinessException("交易员简介不能为空");
|
}
|
|
User party = userService.findByUserId(partyId);
|
|
if (party == null) {
|
throw new BusinessException("用户ID不存在!");
|
}
|
if (Constants.SECURITY_ROLE_TEST.equals(party.getRoleName())) {
|
throw new BusinessException("试用用户无法添加!");
|
}
|
symbols = validateAndNormalizeTraderSymbols(symbols);
|
Trader exist = traderService.findByPartyId(partyId);
|
if (exist != null && exist.getChecked() != -1) {
|
throw new BusinessException("Trader application already exists!");
|
}
|
Trader trader = exist == null ? new Trader() : exist;
|
if (exist == null) {
|
trader.setUuid(ApplicationUtil.getCurrentTimeUUID());
|
trader.setPartyId(partyId);
|
trader.setCreateTime(new Date());
|
}
|
trader.setName(StringUtils.isEmptyString(name)?party.getUserName():name);
|
trader.setSymbols(symbols);
|
trader.setState(state);
|
trader.setImg(img);
|
trader.setRemarks(remarks);
|
trader.setFollowVolumnMin(follow_volumn_min.stripTrailingZeros());
|
trader.setChecked(0);
|
|
String fcType = request.getParameter("follow_commission_type");
|
String fcMonthly = request.getParameter("follow_commission_monthly_amount");
|
String fcDaily = request.getParameter("follow_commission_daily_pct");
|
String normalizedType = FollowCommissionType.normalizeOrLegacy(fcType);
|
trader.setFollowCommissionType(normalizedType);
|
if (FollowCommissionType.isMonthlyFixed(normalizedType)) {
|
BigDecimal m = BigDecimal.ZERO;
|
if (!StringUtils.isEmptyString(fcMonthly)) {
|
try {
|
m = new BigDecimal(fcMonthly.trim());
|
} catch (NumberFormatException e) {
|
throw new BusinessException("月跟单费金额格式不正确");
|
}
|
}
|
if (m.compareTo(BigDecimal.ZERO) <= 0) {
|
throw new BusinessException("按月跟单模式须填写大于 0 的月费用");
|
}
|
trader.setFollowCommissionMonthlyAmount(m);
|
trader.setFollowCommissionDailyPct(0D);
|
} else if (FollowCommissionType.isDailyProfitPct(normalizedType)) {
|
double pct = 0D;
|
if (!StringUtils.isEmptyString(fcDaily)) {
|
try {
|
pct = Double.parseDouble(fcDaily.trim());
|
} catch (NumberFormatException e) {
|
throw new BusinessException("按日利润提成比例格式不正确");
|
}
|
}
|
if (pct <= 0 || pct > 100) {
|
throw new BusinessException("按日利润提成比例须在 0~100 之间");
|
}
|
trader.setFollowCommissionDailyPct(Arith.div(pct, 100));
|
trader.setFollowCommissionMonthlyAmount(BigDecimal.ZERO);
|
} else {
|
trader.setFollowCommissionMonthlyAmount(BigDecimal.ZERO);
|
trader.setFollowCommissionDailyPct(0D);
|
}
|
|
String profitShareParam = request.getParameter("profit_share_ratio");
|
if (FollowCommissionType.isLegacy(normalizedType)) {
|
if (StringUtils.isEmptyString(profitShareParam)) {
|
throw new BusinessException("单笔盈利分成须填写利润分成比例(0~100,单位:%)");
|
}
|
double psPct;
|
try {
|
psPct = Double.parseDouble(profitShareParam.trim());
|
} catch (NumberFormatException e) {
|
throw new BusinessException("利润分成比例格式不正确");
|
}
|
if (psPct <= 0 || psPct > 100) {
|
throw new BusinessException("利润分成比例须在 0~100 之间(单位:%)");
|
}
|
trader.setProfitShareRatio(Arith.div(psPct, 100));
|
} else {
|
trader.setProfitShareRatio(0D);
|
}
|
|
if (exist == null) {
|
traderService.save(trader);
|
} else {
|
traderService.update(trader);
|
}
|
|
|
|
resultObject.setCode("0");
|
resultObject.setMsg("操作成功");
|
} catch (BusinessException e) {
|
resultObject.setCode("1");
|
resultObject.setMsg(e.getMessage());
|
} catch (NumberFormatException e) {
|
resultObject.setCode("1");
|
resultObject.setMsg("最小跟单币数量格式不正确");
|
} catch (Throwable t) {
|
logger.error("UserAction.register error ", t);
|
resultObject.setCode("1");
|
resultObject.setMsg(t.getMessage());
|
}
|
return resultObject;
|
|
}
|
|
/**
|
* 显示带单设置
|
* @param request
|
* @return
|
*/
|
@RequestMapping("showfollowsetting.action")
|
public Object show_follow_setting(HttpServletRequest request){
|
ResultObject resultObject = new ResultObject();
|
resultObject.setCode("1");
|
resultObject.setMsg("跟单利息设置功能已下线");
|
resultObject.setData(null);
|
return resultObject;
|
}
|
|
/**
|
* 跟单设置
|
* @param request
|
* @return
|
*/
|
@RequestMapping("followsetting.action")
|
public Object follow_setting(HttpServletRequest request){
|
ResultObject resultObject = new ResultObject();
|
resultObject.setCode("1");
|
resultObject.setMsg("跟单利息设置功能已下线");
|
return resultObject;
|
}
|
|
/**
|
* 跟单设置
|
* @param request
|
* @return
|
*/
|
@RequestMapping("updatefollowsetting.action")
|
public Object update_follow_setting(HttpServletRequest request){
|
ResultObject resultObject = new ResultObject();
|
resultObject.setCode("1");
|
resultObject.setMsg("跟单利息设置功能已下线");
|
return resultObject;
|
}
|
|
private String verification(String name, String img, String symbols, int order_profit, int deviation_order_profit, int order_loss,
|
int deviation_order_loss, double week_3_order_amount, double deviation_week_3_order_amount, int week_3_order_profit,
|
int deviation_week_3_order_profit, int week_3_order_sum, int deviation_week_3_order_sum, double order_amount, double deviation_order_amount,
|
int follower_sum, int deviation_follower_sum, int follower_now, int deviation_follower_now, double profit_share_ratio, int follower_max, double follow_volumn_min) {
|
if (StringUtils.isEmptyString(name))
|
return "请输入交易员名称";
|
if (StringUtils.isEmptyString(img))
|
return "请上传交易员头像";
|
|
// if (StringUtils.isEmptyString(this.remarks))
|
// return "请输入交易员简介";
|
if (StringUtils.isEmptyString(symbols))
|
return "请输入带币品种";
|
// if (Arith.add(this.profit,this.deviation_profit) < 0.0D)
|
// return "累计收益加偏差值不能小于0";
|
// if (Arith.add(this.profit_ratio,this.deviation_profit_ratio) < 0.0D)
|
// return "累计收益率加偏差值不能小于0";
|
if (Arith.add(order_profit, deviation_order_profit) < 0)
|
return "累计盈利笔数加偏差值不能小于0";
|
if (Arith.add(order_loss, deviation_order_loss) < 0)
|
return "累计亏损笔数加偏差值不能小于0";
|
// if (Arith.add(this.week_3_profit,this.deviation_week_3_profit) < 0.0D)
|
// return "近3周收益加偏差值不能小于0";
|
if (Arith.add(week_3_order_amount, deviation_week_3_order_amount) < 0.0D)
|
return "近3周累计金额加偏差值不能小于0";
|
// if (Arith.add(this.week_3_profit_ratio,this.deviation_week_3_profit_ratio) < 0.0D)
|
// return "近3周收益率加偏差值不能小于0";
|
if (Arith.add(week_3_order_profit, deviation_week_3_order_profit) < 0)
|
return "近3周盈利笔数加偏差值不能小于0";
|
if (Arith.add(week_3_order_sum, deviation_week_3_order_sum) < 0)
|
return "近3周交易笔数加偏差值不能小于0";
|
if (Arith.add(order_amount, deviation_order_amount) < 0.0D)
|
return "累计金额加偏差值不能小于0";
|
if (Arith.add(follower_sum, deviation_follower_sum) < 0)
|
return "累计跟随加偏差值人数不能小于0";
|
if (Arith.add(follower_now, deviation_follower_now) < 0)
|
return "当前跟随人数加偏差值不能小于0";
|
if (profit_share_ratio < 0.0D)
|
return "利润分成比例不能小于0";
|
if (follow_volumn_min < 0)
|
return "最小跟单张数不能小于0";
|
return null;
|
}
|
|
private Map<String, Object> bulidData(Trader entity, String type, String symbol, Page page) throws ParseException {
|
DecimalFormat df2 = new DecimalFormat("#.##");
|
List<Map<String, Object>> trader_order = new ArrayList<Map<String, Object>>();
|
List<Map<String, Object>> trader_user = new ArrayList<Map<String, Object>>();
|
/**
|
* 跟随用户
|
*/
|
if ("user".equals(type)) {
|
trader_user = traderFollowUserService.getPaged(page, entity.getPartyId(), null);
|
// if (trader_user != null) {
|
// for (Map<String, Object> follow_user : trader_user) {
|
// String username = follow_user.get("name").toString();
|
// char[] username_char = username.toCharArray();
|
// StringBuffer sb = new StringBuffer();
|
// if (username_char.length > 6) {
|
// for (int i = 0; i < username_char.length; i++) {
|
// String aa = "";
|
// if (i < 6) {
|
// aa = String.valueOf(username_char[i]).replaceAll(String.valueOf(username_char[i]), "*");
|
// } else {
|
// aa = String.valueOf(username_char[i]);
|
// }
|
// sb.append(aa);
|
// }
|
// } else {
|
// for (int i = 0; i < username_char.length; i++) {
|
// String aa = "";
|
// if (i < username_char.length) {
|
// aa = String.valueOf(username_char[i]).replaceAll(String.valueOf(username_char[i]), "*");
|
// } else {
|
// aa = String.valueOf(username_char[i]);
|
// }
|
// sb.append(aa);
|
// }
|
// }
|
// follow_user.put("name", sb);
|
// }
|
// }
|
} else if("orders".equals(type)){
|
/**
|
* 查询类型 orders 当前委托 ,hisorders 历史委托 ,user 跟随者
|
*/
|
trader_order = this.contractOrderService.buildDataFromOrders(
|
this.contractOrderService.findSubmittedTraderOwn(entity.getPartyId(), symbol));
|
} else if("hisorders".equals(type)) {
|
trader_order = this.traderOrderService.getPaged(page, entity.getPartyId());
|
}
|
if (trader_order != null) {
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
for (Map<String, Object> order : trader_order) {
|
if (null != order.get("create_time")) {
|
// 确认下数据库中提取出来的值类型是 string, 还是 Date TODO
|
logger.info("------> ApiTraderController.bulidData 时间值类型为:" + order.get("create_time"));
|
Date curCreateTime = DateUtils.toDate(sdf.format(order.get("create_time")), DateUtils.DF_yyyyMMddHHmmss);
|
Date showCreateTime = DateTimeTools.transferToShowTime(curCreateTime);
|
order.put("create_time", DateUtils.format(showCreateTime,"MM-dd HH:mm:ss"));
|
} else {
|
order.put("create_time", "");
|
}
|
|
if (order.get("close_time") != null && !"".equals(order.get("close_time"))) {
|
Date curCloseTime = DateUtils.toDate(sdf.format(order.get("close_time")), DateUtils.DF_yyyyMMddHHmmss);
|
Date showCloseTime = DateTimeTools.transferToShowTime(curCloseTime);
|
order.put("close_time", DateUtils.format(showCloseTime,"MM-dd HH:mm:ss"));
|
} else {
|
order.put("close_time", "");
|
}
|
|
if (order.get("create_time_ts") != null
|
&& StrUtil.isNotBlank(order.get("create_time_ts").toString())
|
&& !Objects.equals(order.get("create_time_ts").toString(), "0")) {
|
String oneValue = order.get("create_time_ts").toString();
|
Long timestamp = Long.parseLong(oneValue);
|
long showTimestamp = DateTimeTools.transferShowTimeToClientTime(timestamp);
|
order.put("create_time_ts", String.valueOf(showTimestamp));
|
}
|
}
|
}
|
|
Map<String, Object> map = new HashMap<String, Object>();
|
String path = Constants.WEB_URL + "/public/showimg!showImg.action?imagePath=" + entity.getImg();
|
map.put("img", path);
|
map.put("trader_order", trader_order);
|
map.put("trader_user", trader_user);
|
map.put("id", entity.getUuid());
|
|
map.put("name", entity.getName());
|
map.put("remarks", entity.getRemarks());
|
/** 带单品种(与 T_TRADER.SYMBOLS 一致;交易员广场列表用 symbol_name,此处双字段避免前端遗漏) */
|
String symbolsVal = StringUtils.isEmptyString(entity.getSymbols()) ? "" : entity.getSymbols();
|
map.put("symbols", symbolsVal);
|
map.put("symbol_name", symbolsVal);
|
/** 带单开关:0 停止 1 开启 2 禁止(与后台交易员管理一致) */
|
map.put("state", StringUtils.isEmptyString(entity.getState()) ? "" : entity.getState());
|
/**
|
* 累计金额order_amount
|
*/
|
map.put("order_amount", df2.format(Arith.add(entity.getOrderAmount(), entity.getDeviationOrderAmount())));
|
|
// map.put("symbol_name", "BTC/USDT;ETH/USDT");
|
double historyProfitTotal = contractOrderService.historyProfitForTraderTotalYield(entity);
|
map.put("profit", df2.format(historyProfitTotal));
|
|
map.put("order_profit", (int) Arith.add(entity.getOrderProfit(), entity.getDeviationOrderProfit()));
|
|
map.put("order_loss", (int) Arith.add(entity.getOrderLoss(), entity.getDeviationOrderLoss()));
|
map.put("order_sum", (int) Arith.add(Arith.add(entity.getOrderProfit(), entity.getOrderLoss()),
|
Arith.add(entity.getDeviationOrderProfit(), entity.getDeviationOrderLoss())));
|
map.put("follower_sum", (int) Arith.add(entity.getFollowerSum(), entity.getDeviationFollowerSum()));
|
|
map.put("follower_now", (int) Arith.add(entity.getFollowerNow(), entity.getDeviationFollowerNow()));
|
/**
|
* 累计收益率
|
*/
|
map.put("profit_ratio", df2.format(Arith.add(Arith.mul(entity.getDeviationProfitRatio(), 100),
|
Arith.mul(entity.getProfitRatio(), 100))));
|
|
// 与广场 list 一致:历史=合约表已平仓全品种盈亏+偏差;分母优先已平仓保证金合计(与当前持仓 deposit 一致)
|
double historyAmountTotal = contractOrderService.historyAmountBasisForTraderTotalYield(entity);
|
double openProfitAgg = 0D;
|
double openDepositAgg = 0D;
|
List<ContractOrder> openTraderOwn = contractOrderService.findSubmittedTraderOwn(entity.getPartyId(), "");
|
if (openTraderOwn != null) {
|
for (ContractOrder one : openTraderOwn) {
|
if (one == null) {
|
continue;
|
}
|
contractOrderService.wrapProfit(one);
|
openProfitAgg = Arith.add(openProfitAgg, one.getProfit() == null ? 0D : one.getProfit().doubleValue());
|
openDepositAgg = Arith.add(openDepositAgg, one.getDeposit() == null ? 0D : one.getDeposit().doubleValue());
|
}
|
}
|
double totalProfitAgg = Arith.add(historyProfitTotal, openProfitAgg);
|
double totalAmountAgg = Arith.add(historyAmountTotal, openDepositAgg);
|
double totalProfitRatioAgg = 0D;
|
if (totalAmountAgg > 0D) {
|
totalProfitRatioAgg = Arith.mul(Arith.div(totalProfitAgg, totalAmountAgg), 100);
|
}
|
map.put("total_profit", df2.format(totalProfitAgg));
|
map.put("total_profit_ratio", df2.format(totalProfitRatioAgg));
|
|
map.put("profit_share_ratio", Arith.mul(entity.getProfitShareRatio(), 100));
|
map.put("follow_commission_type", FollowCommissionType.normalizeOrLegacy(entity.getFollowCommissionType()));
|
map.put("follow_commission_monthly_amount",
|
entity.getFollowCommissionMonthlyAmount() == null ? "0" : entity.getFollowCommissionMonthlyAmount().stripTrailingZeros().toPlainString());
|
map.put("follow_commission_daily_pct", Arith.mul(entity.getFollowCommissionDailyPct(), 100));
|
map.put("follower_max", entity.getFollowerMax());
|
if (entity.getCreateTime() != null) {
|
map.put("create_time", DateUtils.format(entity.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
|
} else {
|
map.put("create_time", "");
|
}
|
Date date_now = new Date();// 取时单
|
int days = daysBetween(entity.getCreateTime(), date_now);
|
if (days < 0) {
|
days = 0;
|
}
|
map.put("create_days", days);
|
map.put("week_3_profit_ratio", Arith.add(entity.getWeek3ProfitRatio(), entity.getDeviationWeek3ProfitRatio()));
|
map.put("week_3_profit", Arith.add(entity.getWeek3Profit(), entity.getDeviationWeek3Profit()));
|
if(BigDecimal.valueOf(Arith.add(entity.getWeek3OrderSum(), entity.getDeviationWeek3OrderSum())).compareTo(BigDecimal.ZERO) > 0) {
|
map.put("week_3_order_profit", Arith.div(Arith.add(entity.getWeek3OrderProfit(), entity.getDeviationWeek3OrderProfit()), Arith.add(entity.getWeek3OrderSum(), entity.getDeviationWeek3OrderSum())));
|
} else {
|
map.put("week_3_order_profit", "");
|
}
|
|
String partyId = SecurityUtils.getCurrentUserId();
|
// if (!StringUtils.isNullOrEmpty(partyId)) {
|
// session_token = sessionTokenService.savePut(partyId);
|
// map.put("session_token", session_token);
|
// }
|
|
if (partyId != null) {
|
TraderFollowUser user = this.traderFollowUserService
|
.findByPartyIdAndTrader_partyId(partyId, entity.getPartyId());
|
if (user != null) {
|
map.put("follow_relation_exists", true);
|
map.put("follow_volume", user.getVolume());
|
map.put("follow_volume_max", user.getVolumeMax());
|
map.put("follow_type", user.getFollowType());
|
map.put("follow_state", user.getState());
|
map.put("follow_symbol", StringUtils.isEmptyString(user.getSymbol()) ? "" : user.getSymbol());
|
map.put("follow_lever_rate", user.getLeverRate());
|
String followFailReason = StringUtils.isEmptyString(user.getFailReason()) ? "" : user.getFailReason();
|
map.put("follow_fail_reason", followFailReason);
|
map.put("follow_fail_reason_key", followFailReasonKeyI18n(followFailReason));
|
map.put("follow_last_fail_time", user.getLastFailTime());
|
map.put("follow_user_cumulative_profit", df2.format(user.getProfit()));
|
double cumAmt = user.getAmountSum();
|
double cumYieldPct = 0D;
|
if (cumAmt > 0D) {
|
cumYieldPct = Arith.mul(Arith.div(user.getProfit(), cumAmt), 100);
|
}
|
map.put("follow_user_cumulative_yield_pct", df2.format(cumYieldPct));
|
|
// 是否已有成功开仓(仅当前 submitted 持仓算成功) + 当前跟单持仓浮盈亏合计
|
boolean followOpenSuccess = false;
|
String followOpenDirection = "";
|
String followOpenTime = "";
|
String followOpenOrderNo = "";
|
double followMyOpenProfit = 0D;
|
double followMyOpenDeposit = 0D;
|
List<TraderFollowUserOrder> userFollowOrders = traderFollowUserOrderService
|
.findByPartyIdAndTraderPartyIdAndState(partyId, entity.getPartyId(), ContractOrder.STATE_SUBMITTED);
|
if (userFollowOrders != null && !userFollowOrders.isEmpty()) {
|
TraderFollowUserOrder latest = userFollowOrders.get(0);
|
for (TraderFollowUserOrder one : userFollowOrders) {
|
if (one != null && !StringUtils.isEmptyString(one.getUserOrderNo())) {
|
ContractOrder co = contractOrderService.findByOrderNo(one.getUserOrderNo());
|
if (co != null && ContractOrder.STATE_SUBMITTED.equals(co.getState())) {
|
contractOrderService.wrapProfit(co);
|
followMyOpenProfit = Arith.add(followMyOpenProfit,
|
co.getProfit() == null ? 0D : co.getProfit().doubleValue());
|
followMyOpenDeposit = Arith.add(followMyOpenDeposit,
|
co.getDeposit() == null ? 0D : co.getDeposit().doubleValue());
|
}
|
}
|
if (one != null && one.getCreateTime() != null && latest != null
|
&& latest.getCreateTime() != null && one.getCreateTime().after(latest.getCreateTime())) {
|
latest = one;
|
}
|
}
|
if (latest != null && !StringUtils.isEmptyString(latest.getUserOrderNo())) {
|
ContractOrder latestUserOrder = contractOrderService.findByOrderNo(latest.getUserOrderNo());
|
if (latestUserOrder != null && ContractOrder.STATE_SUBMITTED.equals(latestUserOrder.getState())) {
|
followOpenSuccess = true;
|
followOpenDirection = StringUtils.isEmptyString(latestUserOrder.getDirection()) ? ""
|
: latestUserOrder.getDirection();
|
if (latestUserOrder.getCreateTime() != null) {
|
followOpenTime = DateUtils.format(latestUserOrder.getCreateTime(), "yyyy-MM-dd HH:mm:ss");
|
}
|
followOpenOrderNo = latestUserOrder.getOrderNo();
|
}
|
}
|
}
|
map.put("follow_open_success", followOpenSuccess);
|
map.put("follow_open_direction", followOpenDirection);
|
map.put("follow_open_time", followOpenTime);
|
map.put("follow_open_order_no", followOpenOrderNo);
|
map.put("follow_my_open_profit", df2.format(followMyOpenProfit));
|
map.put("follow_my_open_deposit", df2.format(followMyOpenDeposit));
|
double followMyOpenYieldPct = 0D;
|
if (followMyOpenDeposit > 0D) {
|
followMyOpenYieldPct = Arith.mul(Arith.div(followMyOpenProfit, followMyOpenDeposit), 100);
|
}
|
map.put("follow_my_open_yield_pct", df2.format(followMyOpenYieldPct));
|
map.put("follow_monthly_remaining_days",
|
computeFollowMonthlyRemainingDays(entity.getFollowCommissionType(), user));
|
} else {
|
map.put("follow_relation_exists", false);
|
map.put("follow_state", "2");
|
map.put("follow_fail_reason", "");
|
map.put("follow_fail_reason_key", "");
|
map.put("follow_last_fail_time", null);
|
map.put("follow_open_success", false);
|
map.put("follow_open_direction", "");
|
map.put("follow_open_time", "");
|
map.put("follow_open_order_no", "");
|
map.put("follow_user_cumulative_profit", df2.format(0D));
|
map.put("follow_user_cumulative_yield_pct", df2.format(0D));
|
map.put("follow_my_open_profit", df2.format(0D));
|
map.put("follow_my_open_deposit", df2.format(0D));
|
map.put("follow_my_open_yield_pct", df2.format(0D));
|
map.put("follow_monthly_remaining_days", null);
|
}
|
|
} else {
|
map.put("follow_state", "2");
|
map.put("follow_relation_exists", false);
|
map.put("follow_fail_reason", "");
|
map.put("follow_fail_reason_key", "");
|
map.put("follow_user_cumulative_profit", df2.format(0D));
|
map.put("follow_user_cumulative_yield_pct", df2.format(0D));
|
map.put("follow_my_open_profit", df2.format(0D));
|
map.put("follow_my_open_deposit", df2.format(0D));
|
map.put("follow_my_open_yield_pct", df2.format(0D));
|
map.put("follow_monthly_remaining_days", null);
|
map.remove("partyId");
|
}
|
map.put("follow_volumn_min", entity.getFollowVolumnMin() == null ? 0d : entity.getFollowVolumnMin().doubleValue());
|
/** 审核状态:0 待审、1 通过、-1 驳回(供前端在 istrader 异常时从 get 兜底) */
|
map.put("checked", entity.getChecked());
|
return map;
|
|
}
|
|
/** 与 ApiTraderUserController 一致:供 H5/PC i18n 映射跟单失败原因 */
|
private static String followFailReasonKeyI18n(String reason) {
|
if (reason == null) {
|
return "";
|
}
|
String r = reason.trim();
|
if (r.isEmpty()) {
|
return "";
|
}
|
if (r.contains("余额不足")) {
|
return "INSUFFICIENT_BALANCE";
|
}
|
if (r.contains("只能选择交易员带单币种")) {
|
return "SYMBOL_NOT_IN_TRADER_LIST";
|
}
|
if (r.contains("跟单参数输入错误")) {
|
return "INVALID_FOLLOW_PARAMS";
|
}
|
if (r.contains("Insufficient balance") || r.contains("insufficient balance")) {
|
return "INSUFFICIENT_BALANCE";
|
}
|
return "";
|
}
|
|
/**
|
* 月固定跟单费:当前用户对带单员已缴本月费用时,返回本月剩余自然日(含当天);否则 null。
|
*/
|
private Integer computeFollowMonthlyRemainingDays(Object traderCommissionTypeObj, TraderFollowUser user) {
|
if (user == null) {
|
return null;
|
}
|
String typeNorm = traderCommissionTypeObj == null ? FollowCommissionType.LEGACY
|
: FollowCommissionType.normalizeOrLegacy(traderCommissionTypeObj.toString());
|
if (!FollowCommissionType.isMonthlyFixed(typeNorm)) {
|
return null;
|
}
|
String st = user.getState();
|
if (!(TraderFollowUser.STATE_FOLLOWING.equals(st) || TraderFollowUser.STATE_STOPPING.equals(st)
|
|| TraderFollowUser.STATE_FAILED.equals(st))) {
|
return null;
|
}
|
String paid = user.getMonthlyFeePaidPeriod();
|
if (StringUtils.isEmptyString(paid)) {
|
return null;
|
}
|
try {
|
ZoneId z = ZoneId.systemDefault();
|
YearMonth paidYm = YearMonth.parse(paid);
|
YearMonth nowYm = YearMonth.now(z);
|
if (!paidYm.equals(nowYm)) {
|
return null;
|
}
|
LocalDate today = LocalDate.now(z);
|
LocalDate end = nowYm.atEndOfMonth();
|
long days = ChronoUnit.DAYS.between(today, end) + 1L;
|
return (int) Math.max(0L, days);
|
} catch (Exception e) {
|
return null;
|
}
|
}
|
|
public static int daysBetween(Date smdate, Date bdate) throws ParseException {
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
smdate = sdf.parse(sdf.format(smdate));
|
bdate = sdf.parse(sdf.format(bdate));
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(smdate);
|
long time1 = cal.getTimeInMillis();
|
cal.setTime(bdate);
|
long time2 = cal.getTimeInMillis();
|
long between_days = (time2 - time1) / (1000 * 3600 * 24);
|
|
return Integer.parseInt(String.valueOf(between_days));
|
}
|
|
}
|