Skip to content

Commit

Permalink
change open sellorder implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ozgen committed Jan 26, 2024
1 parent 80104bb commit 7387448
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
Expand Down Expand Up @@ -50,9 +51,11 @@ public TickerData getTickerPrice24(String symbol) throws Exception {
List<OrderInfo> getOpenOrders(String symbol) throws Exception {
String openOrdersJson = this.binanceAPI.getOpenOrders(symbol);
List<OrderInfo> orderInfoList = JsonParser.parseOrderInfoJson(openOrdersJson);

List<OrderInfo> infoList = orderInfoList.stream()
.filter(orderInfo -> "BUY".equals(orderInfo.getSide()))
.collect(Collectors.toList());
log.info("'{}' of symbol open orders data are parsed, successfully.", symbol);
return this.binanceOrderService.createOrderInfos(orderInfoList);
return this.binanceOrderService.createOrderInfos(infoList);
}

List<OpenOrder> cancelOpenOrders(String symbol) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.ozgen.telegrambinancebot.configuration.properties.ScheduleConfiguration;
import com.ozgen.telegrambinancebot.model.ProcessStatus;
import com.ozgen.telegrambinancebot.model.bot.BuyOrder;
import com.ozgen.telegrambinancebot.model.bot.SellOrder;
import com.ozgen.telegrambinancebot.model.events.ErrorEvent;
import com.ozgen.telegrambinancebot.model.events.NewSellOrderEvent;
import com.ozgen.telegrambinancebot.model.telegram.TradingSignal;
Expand All @@ -17,6 +18,7 @@

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
Expand All @@ -30,16 +32,48 @@ public class BinanceOpenSellOrderManager {

public void processOpenSellOrders() {
Date searchDate = getSearchDate();
List<TradingSignal> tradingSignals = this.tradingSignalService.getTradingSignalsAfterDateAndIsProcessIn(searchDate, List.of(ProcessStatus.BUY));
if (tradingSignals.isEmpty()){
List<TradingSignal> tradingSignals = this.tradingSignalService
.getTradingSignalsAfterDateAndIsProcessIn(searchDate, List.of(ProcessStatus.BUY));
if (tradingSignals.isEmpty()) {
log.info("No trading signal has been detected.");
return;
}

List<BuyOrder> buyOrders = this.botOrderService.getBuyOrders(tradingSignals);

buyOrders.forEach(this::safelyPublishNewSellOrder);
}

public void processNotCompletedSellOrders() {
Date searchDate = getSearchDate();
List<TradingSignal> sellSignals = this.tradingSignalService
.getTradingSignalsAfterDateAndIsProcessIn(searchDate, List.of(ProcessStatus.SELL));

if (sellSignals.isEmpty()) {
log.info("No trading signal has been detected.");
return;
}
List<SellOrder> sellOrders = this.botOrderService.getSellOrders(sellSignals);
List<BuyOrder> buyOrders = this.botOrderService.getBuyOrders(sellSignals);
List<BuyOrder> matchingOrders = this.findMatchingOrders(sellOrders, buyOrders);
if (matchingOrders.isEmpty()) {
log.info("No matching has been detected.");
return;
}
matchingOrders.forEach(this::safelyPublishNewSellOrder);
}

private List<BuyOrder> findMatchingOrders(List<SellOrder> sellOrders, List<BuyOrder> buyOrders) {
return buyOrders.stream()
.filter(buyOrder -> {
TradingSignal buySignal = buyOrder.getTradingSignal();
return sellOrders.stream()
.anyMatch(sellOrder -> sellOrder.getTradingSignal().getId().equals(buySignal.getId()) &&
sellOrder.getCoinAmount() < buyOrder.getCoinAmount());
})
.collect(Collectors.toList());
}

private void safelyPublishNewSellOrder(BuyOrder buyOrder) {
try {
this.publishNewSellOrder(buyOrder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface SellOrderRepository extends JpaRepository<SellOrder, String> {

Optional<SellOrder> findByTradingSignal(TradingSignal tradingSignal);
List<SellOrder> findByTradingSignalIn(List<TradingSignal> tradingSignals);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.ozgen.telegrambinancebot.scheduling.binance;

import com.ozgen.telegrambinancebot.manager.binance.BinanceOpenSellOrderManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class BinanceNotCompletedSellOrderScheduler {

private final BinanceOpenSellOrderManager binanceOpenSellOrderManager;


@Scheduled(fixedRateString = "#{${app.bot.schedule.openSellOrder}}")
public void processNotCompletedSellOrders() {
log.info("NotCompletedSellOrderScheduler has been started");
this.binanceOpenSellOrderManager.processNotCompletedSellOrders();
log.info("NotCompletedSellOrderScheduler has been finished");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,15 @@ public List<BuyOrder> getBuyOrders(List<TradingSignal> tradingSignals) {
return List.of(); // Return an empty list in case of error
}
}

public List<SellOrder> getSellOrders(List<TradingSignal> tradingSignals) {
try {
List<SellOrder> sellOrders = sellOrderRepository.findByTradingSignalIn(tradingSignals);
log.info("Retrieved {} sell orders for trading signals", sellOrders.size());
return sellOrders;
} catch (Exception e) {
log.error("Error retrieving buy orders: {}", e.getMessage(), e);
return List.of(); // Return an empty list in case of error
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.ozgen.telegrambinancebot.configuration.properties.ScheduleConfiguration;
import com.ozgen.telegrambinancebot.model.ProcessStatus;
import com.ozgen.telegrambinancebot.model.bot.BuyOrder;
import com.ozgen.telegrambinancebot.model.bot.SellOrder;
import com.ozgen.telegrambinancebot.model.events.NewSellOrderEvent;
import com.ozgen.telegrambinancebot.model.telegram.TradingSignal;
import com.ozgen.telegrambinancebot.service.BotOrderService;
Expand Down Expand Up @@ -33,11 +34,14 @@ public class BinanceOpenSellOrderManagerTest {

private static final String SYMBOL = "BNBBTC";
private static final Double BUY_PRICE = 0.01;
private static final Double SELL_PRICE = 0.011;
private static final String START_ENTRY = "0.009";
private static final String END_ENTRY = "0.011";

private static final String STOPLOSS = "0.008";
private static final Double BNB_TOTAL_AMOUNT = 0.23;
private static final Double BNB_LESS_AMOUNT = 0.13;
private static final String SIGNAL_ID = "signal_id";

@Mock
private TradingSignalService tradingSignalService;
Expand All @@ -56,10 +60,14 @@ public class BinanceOpenSellOrderManagerTest {

private BuyOrder buyOrder;

private SellOrder sellOrder;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);

when(this.tradingSignal.getId())
.thenReturn(SIGNAL_ID);
when(this.tradingSignal.getSymbol())
.thenReturn(SYMBOL);
when(this.tradingSignal.getEntryStart())
Expand All @@ -80,6 +88,13 @@ void setUp() {
this.buyOrder.setCoinAmount(BNB_TOTAL_AMOUNT);
this.buyOrder.setStopLoss(0.012);
this.buyOrder.setTradingSignal(this.tradingSignal);

this.sellOrder = new SellOrder();
this.sellOrder.setSymbol(SYMBOL);
this.sellOrder.setSellPrice(SELL_PRICE);
this.sellOrder.setCoinAmount(BNB_LESS_AMOUNT);
this.sellOrder.setStopLoss(0.012);
this.sellOrder.setTradingSignal(this.tradingSignal);
}

@Test
Expand Down Expand Up @@ -173,4 +188,91 @@ public void testProcessOpenSellOrders_withException() {
mockedSyncUtil.close();
}
}

@Test
public void testProcessNotCompletedSellOrders_Success() {
// Arrange
when(this.tradingSignalService.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL))))
.thenReturn(List.of(this.tradingSignal));
when(this.botOrderService.getSellOrders(argThat(list -> list.contains(this.tradingSignal))))
.thenReturn(List.of(this.sellOrder));
when(this.botOrderService.getBuyOrders(argThat(list -> list.contains(this.tradingSignal))))
.thenReturn(List.of(this.buyOrder));

// Act
this.binanceOpenSellOrderManager.processNotCompletedSellOrders();

// Assert
verify(this.tradingSignalService)
.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL)));
verify(this.botOrderService)
.getBuyOrders(argThat(list -> list.contains(this.tradingSignal)));
ArgumentCaptor<NewSellOrderEvent> eventCaptor = ArgumentCaptor.forClass(NewSellOrderEvent.class);
verify(this.publisher)
.publishEvent(eventCaptor.capture());
NewSellOrderEvent newSellOrderEvent = eventCaptor.getValue();
assertEquals(this.buyOrder, newSellOrderEvent.getBuyOrder());
}

@Test
public void testProcessNotCompletedSellOrders_withEmptyBuyOrders() {
// Arrange
when(this.tradingSignalService.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL))))
.thenReturn(List.of(this.tradingSignal));
when(this.botOrderService.getSellOrders(argThat(list -> list.contains(this.tradingSignal))))
.thenReturn(List.of(this.sellOrder));
when(this.botOrderService.getBuyOrders(argThat(list -> list.contains(this.tradingSignal))))
.thenReturn(List.of());

// Act
this.binanceOpenSellOrderManager.processNotCompletedSellOrders();

// Assert
verify(this.tradingSignalService)
.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL)));
verify(this.botOrderService)
.getBuyOrders(argThat(list -> list.contains(this.tradingSignal)));
verify(this.publisher, never())
.publishEvent(any());
}

@Test
public void testProcessNotCompletedSellOrders_withEmptySellOrders() {
// Arrange
when(this.tradingSignalService.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL))))
.thenReturn(List.of(this.tradingSignal));
when(this.botOrderService.getSellOrders(argThat(list -> list.contains(this.tradingSignal))))
.thenReturn(List.of());
when(this.botOrderService.getBuyOrders(argThat(list -> list.contains(this.tradingSignal))))
.thenReturn(List.of(this.buyOrder));

// Act
this.binanceOpenSellOrderManager.processNotCompletedSellOrders();

// Assert
verify(this.tradingSignalService)
.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL)));
verify(this.botOrderService)
.getBuyOrders(argThat(list -> list.contains(this.tradingSignal)));
verify(this.publisher, never())
.publishEvent(any());
}

@Test
public void testProcessNotCompletedSellOrders_withEmptyTradingSignalList() {
// Arrange
when(this.tradingSignalService.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL))))
.thenReturn(List.of());

// Act
this.binanceOpenSellOrderManager.processNotCompletedSellOrders();

// Assert
verify(this.tradingSignalService)
.getTradingSignalsAfterDateAndIsProcessIn(any(), argThat(list -> list.contains(ProcessStatus.SELL)));
verify(this.botOrderService, never())
.getBuyOrders(any());
verify(this.publisher, never())
.publishEvent(any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.TestPropertySource;

import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@DataJpaTest
Expand Down Expand Up @@ -44,5 +46,12 @@ public void testFindByTradingSignal() {
assertTrue(foundOrder.isPresent());
assertEquals(this.sellOrder, foundOrder.get());
}

@Test
public void testFindByTradingSignalIn() {
List<SellOrder> foundOrder = this.sellOrderRepository.findByTradingSignalIn(List.of(this.tradingSignal));
assertFalse(foundOrder.isEmpty());
assertEquals(1, foundOrder.size());
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.ozgen.telegrambinancebot.scheduling.binance;

import com.ozgen.telegrambinancebot.manager.binance.BinanceOpenSellOrderManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.verify;


public class BinanceNotCompletedSellOrderSchedulerTest {

@Mock
private BinanceOpenSellOrderManager binanceOpenSellOrderManager;

@InjectMocks
private BinanceNotCompletedSellOrderScheduler binanceNotCompletedSellOrderScheduler;

@BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
}

@Test
public void testProcessOpenSellOrders() {
this.binanceNotCompletedSellOrderScheduler.processNotCompletedSellOrders();

verify(this.binanceOpenSellOrderManager)
.processNotCompletedSellOrders();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,32 @@ public void testGetBuyOrders_Exception() {
verify(buyOrderRepository)
.findByTradingSignalIn(signals);
}

@Test
public void testGetSellOrders_Success() {
List<TradingSignal> signals = List.of(new TradingSignal());
List<SellOrder> expectedOrders = List.of(new SellOrder());
when(this.sellOrderRepository.findByTradingSignalIn(signals))
.thenReturn(expectedOrders);

List<SellOrder> result = this.botOrderService.getSellOrders(signals);

assertNotNull(result);
assertEquals(expectedOrders, result);
verify(this.sellOrderRepository)
.findByTradingSignalIn(signals);
}

@Test
public void testGetSellOrders_Exception() {
List<TradingSignal> signals = List.of(new TradingSignal());
when(this.sellOrderRepository.findByTradingSignalIn(signals))
.thenThrow(new RuntimeException("Test exception"));

List<SellOrder> result = this.botOrderService.getSellOrders(signals);

assertTrue(result.isEmpty());
verify(this.sellOrderRepository)
.findByTradingSignalIn(signals);
}
}

0 comments on commit 7387448

Please sign in to comment.