Helius
2020-08-06 fe0f38889f72cb517ca995a55b8d5a40c2127ec8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
package com.xcong.excoin.modules.contract.service.impl;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.xcong.excoin.common.enumerates.CoinTypeEnum;
import com.xcong.excoin.common.enumerates.OrderClosingTypeEnum;
import com.xcong.excoin.common.system.service.CommonService;
import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao;
import com.xcong.excoin.modules.contract.dao.ContractOrderDao;
import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
import com.xcong.excoin.modules.contract.entity.ContractOrderEntity;
import com.xcong.excoin.modules.contract.mapper.ContractHoldOrderEntityMapper;
import com.xcong.excoin.modules.contract.service.RabbitOrderService;
import com.xcong.excoin.modules.documentary.common.NoticeConstant;
import com.xcong.excoin.modules.documentary.dao.FollowFollowerOrderRelationDao;
import com.xcong.excoin.modules.documentary.dao.FollowFollowerProfitDao;
import com.xcong.excoin.modules.documentary.dao.FollowTraderInfoDao;
import com.xcong.excoin.modules.documentary.dao.FollowTraderProfitDetailDao;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerOrderRelationEntity;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerProfitEntity;
import com.xcong.excoin.modules.documentary.entity.FollowTraderInfoEntity;
import com.xcong.excoin.modules.documentary.entity.FollowTraderProfitDetailEntity;
import com.xcong.excoin.modules.documentary.service.FollowOrderOperationService;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
import com.xcong.excoin.modules.member.entity.AgentReturnEntity;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity;
import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
import com.xcong.excoin.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
 
/**
 * @author wzy
 * @date 2020-06-01
 **/
@Slf4j
@Service
public class RabbitOrderServiceImpl implements RabbitOrderService {
 
    @Resource
    private MemberDao memberDao;
 
    @Resource
    private OrderWebsocketServiceImpl orderWebsocketService;
 
    @Resource
    private ContractHoldOrderDao contractHoldOrderDao;
 
    @Resource
    private ContractOrderDao contractOrderDao;
 
    @Resource
    private CommonService commonService;
 
    @Resource
    private MemberWalletContractDao memberWalletContractDao;
 
    @Resource
    private CacheSettingUtils cacheSettingUtils;
 
    @Resource
    private RedisUtils redisUtils;
 
    @Resource
    private FollowFollowerOrderRelationDao followFollowerOrderRelationDao;
    @Resource
    private FollowOrderOperationService followOrderOperationService;
    @Resource
    private FollowTraderInfoDao followTraderInfoDao;
    @Resource
    private FollowTraderProfitDetailDao followTraderProfitDetailDao;
    @Resource
    private FollowFollowerProfitDao followFollowerProfitDao;
 
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelHoldOrder(List<Long> ids) {
        if (CollUtil.isNotEmpty(ids)) {
            try {
                if (ids.size() == 1) {
                    ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(ids.get(0));
                    cancelHoldOrderMethod(holdOrderEntity);
                } else {
                    List<ContractHoldOrderEntity> holdOrderEntities = contractHoldOrderDao.selectBatchIds(ids);
                    if (CollUtil.isNotEmpty(holdOrderEntities)) {
                        for (ContractHoldOrderEntity holdOrder : holdOrderEntities) {
                            cancelHoldOrderMethod(holdOrder);
                        }
                    }
                }
            }catch (Exception e) {
                log.error("平仓异常", e);
            }
 
        }
    }
 
    @Transactional(rollbackFor = Exception.class)
    public void cancelHoldOrderMethod(ContractHoldOrderEntity holdOrderEntity) {
        String symbol = holdOrderEntity.getSymbol();
        // 获取最新价
        BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol)));
 
        MemberEntity memberEntity = memberDao.selectById(holdOrderEntity.getMemberId());
 
        MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(holdOrderEntity.getMemberId(), CoinTypeEnum.USDT.name());
        if (walletContract != null) {
            // 删除持仓表订单
            contractHoldOrderDao.deleteById(holdOrderEntity.getId());
 
            BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(symbol);
            // 盈亏
            BigDecimal profitOrLoss = BigDecimal.ZERO;
            Integer orderType = null;
            Integer closingType = null;
            // 开多
            if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) {
                newPrice = newPrice.multiply(BigDecimal.ONE.subtract(memberEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN)));
                // (最新价-开仓价)*规格*张数
                profitOrLoss = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
                orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_MORE;
                closingType = OrderClosingTypeEnum.CLOSE_MORE.getValue();
                // 开空
            } else {
                newPrice = newPrice.multiply(BigDecimal.ONE.add(memberEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN)));
                // (开仓价-最新价)*规格*张数
                profitOrLoss = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt()));
                orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_LESS;
                closingType = OrderClosingTypeEnum.CLOSE_LESS.getValue();
            }
 
            if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) {
                PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
                if (profitOrLoss.compareTo(BigDecimal.ZERO) > -1) {
                    profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam()));
                } else {
                    profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.add(tradeSettingEntity.getProfitParam()));
                }
            }
 
            // 盈亏比例(回报率)
            BigDecimal rewardRatio = profitOrLoss.divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 8, BigDecimal.ROUND_DOWN);
 
            FollowTraderInfoEntity traderInfoEntity = null;
            // 判断当前订单是否为跟单
            if (ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY == holdOrderEntity.getContractType()) {
                // 若不为交易员,则计算跟随者订单返利
                if (!MemberEntity.IS_TRADER_Y.equals(memberEntity.getIsTrader())) {
                    traderInfoEntity = followTraderInfoDao.selectTraderInfoByOrderId(holdOrderEntity.getId());
                    if (profitOrLoss.compareTo(BigDecimal.ZERO) > 0) {
                        // 计算需返利给交易员的金额
                        BigDecimal returnMoney = profitOrLoss.multiply(traderInfoEntity.getProfitRatio());
                        profitOrLoss = profitOrLoss.subtract(returnMoney);
                        MemberWalletContractEntity traderWallet = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(traderInfoEntity.getMemberId(), CoinTypeEnum.USDT.name());
                        memberWalletContractDao.increaseWalletContractBalanceById(returnMoney, returnMoney, null, traderWallet.getId());
                        insertReturnProfitDetail(traderInfoEntity.getMemberId(), memberEntity.getId(), returnMoney, holdOrderEntity.getOrderNo());
                    }
                }
            }
 
            ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity);
            contractOrderEntity.setId(null);
            contractOrderEntity.setOrderType(orderType);
            contractOrderEntity.setClosingPrice(newPrice);
            contractOrderEntity.setClosingFeeAmount(holdOrderEntity.getOpeningFeeAmount());
            contractOrderEntity.setClosingTime(new Date());
            contractOrderEntity.setClosingType(closingType);
            contractOrderEntity.setRewardAmount(profitOrLoss);
            contractOrderEntity.setRewardRatio(rewardRatio);
            contractOrderDao.insert(contractOrderEntity);
 
            // 计算盈利或亏损后可用金额和总金额应该增加或减少的
            BigDecimal addMoney = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()).add(profitOrLoss);
            memberWalletContractDao.increaseWalletContractBalanceById(addMoney, profitOrLoss.subtract(contractOrderEntity.getOpeningFeeAmount()), null, walletContract.getId());
 
            // 流水
            LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), addMoney, walletContract.getAvailableBalance().add(addMoney), holdOrderEntity.getSymbol(), "平仓", "平仓");
 
            // 计算佣金
            ThreadPoolUtils.calReturnMoney(memberEntity.getId(), contractOrderEntity.getClosingFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE);
 
            // 判断当前持仓是否为跟单订单
            if (ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY == holdOrderEntity.getContractType()) {
                updateFollowOrderRelation(holdOrderEntity.getId(), contractOrderEntity.getId());
 
                // 若为交易员,则平仓跟随者订单
                if (MemberEntity.IS_TRADER_Y.equals(memberEntity.getIsTrader())) {
                    followOrderOperationService.closingFollowOrders(holdOrderEntity.getOrderNo());
                } else {
                    followFollowerProfitDao.updateFollowerProfitByTradeMemberId(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), profitOrLoss, traderInfoEntity.getMemberId(), memberEntity.getId());
                    LogRecordUtils.insertFollowerNotice(memberEntity.getId(), NoticeConstant.CLOSE_ORDER_TITLE, StrUtil.format(NoticeConstant.CLOSE_ORDER_CONTENT, contractOrderEntity.getSymbol(), contractOrderEntity.getClosingPrice(), profitOrLoss));
                }
            }
        }
 
    }
 
    /**
     * 更新跟单订单关系
     *
     * @param oldOrderId 当前持仓ID
     * @param newOrderId 历史订单ID
     */
    public void updateFollowOrderRelation(Long oldOrderId, Long newOrderId) {
        FollowFollowerOrderRelationEntity orderRelationEntity = followFollowerOrderRelationDao.selectNowOneByorderId(oldOrderId);
        if (orderRelationEntity != null) {
            orderRelationEntity.setOrderId(newOrderId);
            orderRelationEntity.setOrderType(FollowFollowerOrderRelationEntity.ORDER_TYPE_HISTORY);
            followFollowerOrderRelationDao.updateById(orderRelationEntity);
        }
    }
 
    /**
     * 插入跟单返利明细
     *
     * @param memberId       交易员会员ID
     * @param followMemberId 跟随者会员ID
     * @param amount         返利金额
     * @param orderNo        订单编号
     */
    public void insertReturnProfitDetail(Long memberId, Long followMemberId, BigDecimal amount, String orderNo) {
        FollowTraderProfitDetailEntity profitDetailEntity = new FollowTraderProfitDetailEntity();
        profitDetailEntity.setMemberId(memberId);
        profitDetailEntity.setFollowMemberId(followMemberId);
        profitDetailEntity.setAmount(amount);
        profitDetailEntity.setOrderNo(orderNo);
        followTraderProfitDetailDao.insert(profitDetailEntity);
    }
}