Helius
2020-08-04 ea8eb9c441bb4452d153579b456467b2f5e958e4
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
package com.xcong.excoin.modules.documentary.service.impl;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.common.enumerates.CoinTypeEnum;
import com.xcong.excoin.common.enumerates.RabbitPriceTypeEnum;
import com.xcong.excoin.common.response.Result;
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.ContractEntrustOrderEntity;
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.FollowFollowerSettingDao;
import com.xcong.excoin.modules.documentary.dao.FollowTraderInfoDao;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerOrderRelationEntity;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerProfitEntity;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerSettingEntity;
import com.xcong.excoin.modules.documentary.entity.FollowTraderInfoEntity;
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.rabbit.pricequeue.OrderModel;
import com.xcong.excoin.rabbit.producer.OrderProducer;
import com.xcong.excoin.utils.CacheSettingUtils;
import com.xcong.excoin.utils.CalculateUtil;
import com.xcong.excoin.utils.LogRecordUtils;
import com.xcong.excoin.utils.ThreadPoolUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
/**
 * @author helius
 */
@Slf4j
@Service
public class FollowOrderOperationServiceImpl implements FollowOrderOperationService {
 
    @Resource
    private ContractHoldOrderDao contractHoldOrderDao;
    @Resource
    private FollowFollowerSettingDao followFollowerSettingDao;
    @Resource
    private CacheSettingUtils cacheSettingUtils;
    @Resource
    private FollowFollowerOrderRelationDao followFollowerOrderRelationDao;
    @Resource
    private MemberWalletContractDao memberWalletContractDao;
    @Resource
    private MemberDao memberDao;
    @Resource
    private CommonService commonService;
    @Resource
    private ContractOrderDao contractOrderDao;
    @Resource
    private OrderProducer producer;
    @Resource
    private FollowTraderInfoDao followTraderInfoDao;
 
    @Resource
    private RabbitOrderService rabbitOrderService;
 
 
    @Override
    public void addFollowerOrder(Long id) {
        log.info("进入跟单处理逻辑");
        // 查询交易员订单
        ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(id);
 
        List<FollowFollowerSettingEntity> followerSettings = followFollowerSettingDao.selectAllFollowerSettingByTradeMemberId(holdOrderEntity.getMemberId());
        // 开仓价
        BigDecimal openPrice = holdOrderEntity.getOpeningPrice();
        PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
 
        // 交易员信息
        FollowTraderInfoEntity followTraderInfoEntity = followTraderInfoDao.selectTraderInfoByMemberId(holdOrderEntity.getMemberId());
 
        // 点差
        BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(holdOrderEntity.getSymbol());
        Long tradeMemberId = holdOrderEntity.getMemberId();
        if (CollUtil.isNotEmpty(followerSettings)) {
            for (FollowFollowerSettingEntity followerSetting : followerSettings) {
                // 当前持仓张数
                Integer holdingCnt = followFollowerOrderRelationDao.selectFollowerHoldingSymbolCnt(tradeMemberId, followerSetting.getMemberId());
 
                // 跟单张数 根据跟随者设置,若为固定张数,则为其固定张数,若为固定比例,则与交易员张数相乘。但必须小于最大持仓张数
                int symbolCnt = 0;
                if (followerSetting.getFollowType().equals(FollowFollowerSettingEntity.FOLLOW_TYPE_PIECE)) {
                    symbolCnt = followerSetting.getFollowCnt();
                } else {
                    symbolCnt = followerSetting.getFollowCnt() * holdOrderEntity.getSymbolCnt();
                }
 
                if (followerSetting.getMaxFollowCnt() != null && followerSetting.getMaxFollowCnt() !=0) {
                    // 若张数+当前持仓张数大于最大持仓张数,则取最大持仓减去当前持仓,若差值小于等于0,则不下单
                    if (symbolCnt + holdingCnt > followerSetting.getMaxFollowCnt()) {
                        symbolCnt = followerSetting.getMaxFollowCnt() - holdingCnt;
                    }
 
                    if (symbolCnt <= 0) {
                        LogRecordUtils.insertFollowerNotice(followerSetting.getMemberId(), NoticeConstant.OPEN_ORDER_FOLLOW_FAIL_TITLE, StrUtil.format(NoticeConstant.OPEN_ORDER_FOLLOW_FAIL_CONTENT, followTraderInfoEntity.getNickname()));
                        continue;
                    }
                }
 
                MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(followerSetting.getMemberId(), CoinTypeEnum.USDT.name());
                if (walletContract == null) {
                    log.info("钱包地址不存在:{}", followerSetting.getMemberId());
                    continue;
                }
 
                // 开仓手续费 建仓价*规格*手数*手续费率
                BigDecimal openFeePrice = openPrice.multiply(lotNumber)
                        .multiply(new BigDecimal(symbolCnt))
                        .multiply(tradeSettingEntity.getFeeRatio().divide(new BigDecimal(100)))
                        .setScale(8, BigDecimal.ROUND_DOWN);
 
                // 保证金
                BigDecimal bondAmount = openPrice.multiply(lotNumber).multiply(new BigDecimal(symbolCnt))
                        .multiply(BigDecimal.ONE.divide(new BigDecimal(holdOrderEntity.getLeverRatio())))
                        .setScale(8, BigDecimal.ROUND_DOWN);
 
                // 预付款
                BigDecimal prePaymentAmount = bondAmount.add(openFeePrice).add(openFeePrice);
                if (prePaymentAmount.compareTo(walletContract.getAvailableBalance()) > -1) {
                    log.info("可用金额不足");
                    continue;
                }
 
                MemberEntity memberEntity = memberDao.selectById(followerSetting.getMemberId());
                // 强平价
                BigDecimal forceClosingPrice = CalculateUtil.getForceSetPrice(bondAmount, openPrice, symbolCnt, lotNumber, holdOrderEntity.getOpeningType(), memberEntity);
 
                ContractHoldOrderEntity followHoldOrder = new ContractHoldOrderEntity();
                followHoldOrder.setMemberId(memberEntity.getId());
                followHoldOrder.setOrderNo(commonService.generateOrderNo(memberEntity.getId()));
                followHoldOrder.setPositionType(ContractEntrustOrderEntity.POSITION_TYPE_ADD);
                followHoldOrder.setTradeType(ContractHoldOrderEntity.TRADE_TYPE_MARK);
                followHoldOrder.setSymbol(holdOrderEntity.getSymbol());
                followHoldOrder.setSymbolCnt(symbolCnt);
                followHoldOrder.setSymbolSku(lotNumber);
                followHoldOrder.setLeverRatio(holdOrderEntity.getLeverRatio());
                followHoldOrder.setForceClosingPrice(forceClosingPrice);
                followHoldOrder.setOpeningFeeAmount(openFeePrice);
                followHoldOrder.setOpeningPrice(openPrice);
                followHoldOrder.setOpeningType(holdOrderEntity.getOpeningType());
                followHoldOrder.setMarkPrice(openPrice);
                followHoldOrder.setIsCanClosing(ContractHoldOrderEntity.ORDER_CAN_CLOSING_Y);
                followHoldOrder.setPrePaymentAmount(prePaymentAmount);
                followHoldOrder.setBondAmount(bondAmount.add(openFeePrice));
                followHoldOrder.setOperateNo(1);
                // 设置合约类型
                followHoldOrder.setContractType(ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY);
 
                ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(followHoldOrder);
                contractOrderEntity.setOpeningTime(new Date());
                contractHoldOrderDao.insert(followHoldOrder);
                int i = contractOrderDao.insert(contractOrderEntity);
                if (i > 0) {
                    memberWalletContractDao.increaseWalletContractBalanceById(prePaymentAmount.negate(), openFeePrice.negate(), null, walletContract.getId());
 
                    FollowFollowerOrderRelationEntity relationEntity = new FollowFollowerOrderRelationEntity();
                    relationEntity.setIsShow(FollowFollowerOrderRelationEntity.IS_SHOW_Y);
                    relationEntity.setMemberId(followHoldOrder.getMemberId());
                    relationEntity.setOrderId(followHoldOrder.getId());
                    relationEntity.setOrderType(FollowFollowerOrderRelationEntity.ORDER_TYPE_HOLD);
                    relationEntity.setTradeId(followTraderInfoEntity.getId());
                    relationEntity.setTradeMemberId(followTraderInfoEntity.getMemberId());
                    relationEntity.setTradeOrderNo(holdOrderEntity.getOrderNo());
                    followFollowerOrderRelationDao.insert(relationEntity);
 
                    // 发送爆仓消息
                    sendOrderBombMsg(holdOrderEntity.getId(), holdOrderEntity.getOpeningType(), forceClosingPrice, holdOrderEntity.getSymbol(), holdOrderEntity.getOperateNo());
 
                    // 计算佣金
                    ThreadPoolUtils.calReturnMoney(memberEntity.getId(), contractOrderEntity.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_OPEN);
 
                    // 插入财务流水
                    if (holdOrderEntity.getOpeningType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
                        LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), holdOrderEntity.getSymbol(), "买涨持仓", "买涨:" + holdOrderEntity.getSymbol());
                        LogRecordUtils.insertFollowerNotice(memberEntity.getId(), NoticeConstant.OPEN_ORDER_TITLE, StrUtil.format(NoticeConstant.OPEN_ORDER_CONTENT, holdOrderEntity.getSymbol() + "开多", openPrice, followTraderInfoEntity.getNickname()));
                    } else {
                        LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), holdOrderEntity.getSymbol(), "买跌持仓", "买跌:" + holdOrderEntity.getSymbol());
                        LogRecordUtils.insertFollowerNotice(memberEntity.getId(), NoticeConstant.OPEN_ORDER_TITLE, StrUtil.format(NoticeConstant.OPEN_ORDER_CONTENT, holdOrderEntity.getSymbol() + "开空", openPrice, followTraderInfoEntity.getNickname()));
                    }
                }
            }
        }
    }
 
    public void sendOrderBombMsg(Long id, int type, BigDecimal forceClosingPrice, String symbol, int operateNo) {
        OrderModel model = null;
        // 开多
        if (ContractHoldOrderEntity.OPENING_TYPE_MORE == type) {
            model = new OrderModel(id, RabbitPriceTypeEnum.CLOSE_MORE_BOMB.getValue(), forceClosingPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), symbol, operateNo);
            // 开空
        } else {
            model = new OrderModel(id, RabbitPriceTypeEnum.CLOSE_LESS_BOMB.getValue(), forceClosingPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), symbol, operateNo);
        }
        producer.sendPriceOperate(JSONObject.toJSONString(model));
    }
 
 
    @Override
    public void closingFollowOrders(String orderNo) {
        List<FollowFollowerOrderRelationEntity> orderRelations = followFollowerOrderRelationDao.selectFollowHoldOrderByTradeOrderNo(orderNo);
        if (CollUtil.isNotEmpty(orderRelations)) {
            for (FollowFollowerOrderRelationEntity orderRelation : orderRelations) {
                List<Long> ids= new ArrayList<>();
                ids.add(orderRelation.getOrderId());
                rabbitOrderService.cancelHoldOrder(ids);
            }
        }
    }
}