use of tech.cassandre.trading.bot.dto.util.GainDTO in project cassandre-trading-bot by cassandre-tech.
the class PositionServiceTest method checkClosePosition.
@Test
@DisplayName("Check close position")
public void checkClosePosition() {
// =============================================================================================================
// Creates position 1 (ETH/BTC, 0.0001, 100% stop gain).
final PositionCreationResultDTO creationResult1 = strategy.createLongPosition(ETH_BTC, new BigDecimal("0.0001"), PositionRulesDTO.builder().stopGainPercentage(100f).build());
final long position1Uid = creationResult1.getPosition().getUid();
assertEquals("ORDER00010", creationResult1.getPosition().getOpeningOrder().getOrderId());
// We retrieve the order from the service, and we wait for the order to update the position.
// Only one order updates (we don't send the PENDING_NOW order in flux).
// Two positions updates because order status change from PENDING_NEW to NEW.
orderFlux.update();
await().untilAsserted(() -> assertEquals(1, strategy.getOrdersUpdatesReceived().size()));
await().untilAsserted(() -> assertEquals(2, strategy.getPositionsUpdatesReceived().size()));
// This trade complets the opening order so the position moves to OPENED status.
tradeFlux.emitValue(TradeDTO.builder().tradeId("000002").type(BID).orderId("ORDER00010").currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("0.0001", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("0.2", ETH_BTC.getQuoteCurrency())).build());
await().untilAsserted(() -> assertEquals(OPENED, getPositionDTO(position1Uid).getStatus()));
// =============================================================================================================
// We send tickers.
// A first ticker arrives with a gain of 100% but for the wrong CP - so it must still be OPENED.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_USDT).last(new BigDecimal("0.5")).build());
await().untilAsserted(() -> assertEquals(3, strategy.getPositionsUpdatesReceived().size()));
PositionDTO p = getPositionDTO(position1Uid);
assertEquals(OPENED, p.getStatus());
// We check the last calculated gain - should be none.
Optional<GainDTO> gain = p.getLatestCalculatedGain();
assertFalse(gain.isPresent());
// A second ticker arrives with a gain of 50%.
// From 0.2 (trade) to 0.3 (ticker).
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("0.3")).build());
await().untilAsserted(() -> assertEquals(4, strategy.getPositionsUpdatesReceived().size()));
p = getPositionDTO(position1Uid);
// We check the last calculated gain - should be 50%.
gain = p.getLatestCalculatedGain();
// Check the calculated gains.
assertTrue(gain.isPresent());
assertEquals(50, gain.get().getPercentage());
assertEquals(0, new BigDecimal("0.00001").compareTo(gain.get().getAmount().getValue()));
assertEquals(BTC, gain.get().getAmount().getCurrency());
}
use of tech.cassandre.trading.bot.dto.util.GainDTO in project cassandre-trading-bot by cassandre-tech.
the class GainDTOTest method isSuperiorTo.
@Test
@DisplayName("Check isSuperiorTo() method")
public void isSuperiorTo() {
GainDTO gain = GainDTO.builder().percentage(2).amount(new CurrencyAmountDTO(new BigDecimal("2"), BTC)).build();
GainDTO inferiorGain = GainDTO.builder().percentage(1).amount(new CurrencyAmountDTO(new BigDecimal("2"), BTC)).build();
GainDTO superiorGain = GainDTO.builder().percentage(3).amount(new CurrencyAmountDTO(new BigDecimal("2"), BTC)).build();
assertTrue(gain.isSuperiorTo(inferiorGain));
assertFalse(gain.isSuperiorTo(superiorGain));
assertTrue(gain.isSuperiorTo(GainDTO.ZERO));
}
use of tech.cassandre.trading.bot.dto.util.GainDTO in project cassandre-trading-bot by cassandre-tech.
the class GainDTOTest method checkIsInferiorTO.
@Test
@DisplayName("Check isInferiorTo() method")
public void checkIsInferiorTO() {
GainDTO gain = GainDTO.builder().percentage(2).amount(new CurrencyAmountDTO(new BigDecimal("2"), BTC)).build();
GainDTO inferiorGain = GainDTO.builder().percentage(1).amount(new CurrencyAmountDTO(new BigDecimal("2"), BTC)).build();
GainDTO superiorGain = GainDTO.builder().percentage(3).amount(new CurrencyAmountDTO(new BigDecimal("2"), BTC)).build();
assertFalse(gain.isInferiorTo(inferiorGain));
assertTrue(gain.isInferiorTo(superiorGain));
assertFalse(gain.isInferiorTo(GainDTO.ZERO));
}
use of tech.cassandre.trading.bot.dto.util.GainDTO in project cassandre-trading-bot by cassandre-tech.
the class PositionLongFluxTest method checkReceivedData.
@Test
@DisplayName("Check received data")
public void checkReceivedData() {
// =============================================================================================================
// Creates long position n°1 - 10 ETH bought with BTC.
// Position will be closed if 1 000% gain or 100% loss.
final PositionCreationResultDTO position1Result = strategy.createLongPosition(ETH_BTC, new BigDecimal("10"), PositionRulesDTO.builder().stopGainPercentage(// 1 000% max gain.
1_000f).stopLossPercentage(// 100% max lost.
100f).build());
assertEquals("ORDER00010", position1Result.getPosition().getOpeningOrder().getOrderId());
long position1Uid = position1Result.getPosition().getUid();
// onPositionStatusUpdate - Position 1 should arrive (OPENING).
// 1 position status update:
// - The position is created with the OPENING status.
await().untilAsserted(() -> assertEquals(1, strategy.getPositionsStatusUpdatesCount()));
PositionDTO p = strategy.getLastPositionStatusUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(OPENING, p.getStatus());
assertEquals("Long position n°1 of 10 ETH (rules: 1000.0 % gain / 100.0 % loss) - Opening - Waiting for the trades of order ORDER00010", p.getDescription());
// onPositionUpdate - Position 1 should arrive (OPENING).
// 2 positions updates:
// - Position created with a local order saved in database (Order with status PENDING_NEW).
// - Position updated with the local order retrieved from getOrders with status NEW.
await().untilAsserted(() -> assertEquals(2, strategy.getPositionsUpdatesReceived().size()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(OPENING, p.getStatus());
// Check data in strategy & database.
assertEquals(1, positionRepository.count());
assertEquals(1, strategy.getPositions().size());
Optional<PositionDTO> p1 = strategy.getPositionByPositionId(position1Uid);
assertTrue(p1.isPresent());
assertEquals(1, p1.get().getUid());
assertEquals(1, p1.get().getPositionId());
assertEquals(LONG, p1.get().getType());
assertNotNull(p1.get().getStrategy());
assertEquals(1, p1.get().getStrategy().getUid());
assertEquals("01", p1.get().getStrategy().getStrategyId());
assertEquals(ETH_BTC, p1.get().getCurrencyPair());
assertEquals(0, new BigDecimal("10").compareTo(p1.get().getAmount().getValue()));
assertEquals(ETH_BTC.getBaseCurrency(), p1.get().getAmount().getCurrency());
assertTrue(p1.get().getRules().isStopGainPercentageSet());
assertEquals(1_000f, p1.get().getRules().getStopGainPercentage());
assertTrue(p1.get().getRules().isStopLossPercentageSet());
assertEquals(100f, p1.get().getRules().getStopLossPercentage());
assertEquals(OPENING, p1.get().getStatus());
assertEquals("ORDER00010", p1.get().getOpeningOrder().getOrderId());
assertEquals("ORDER00010", p1.get().getOpeningOrder().getOrderId());
assertTrue(p1.get().getOpeningOrder().getTrades().isEmpty());
assertNull(p1.get().getClosingOrder());
assertNull(p1.get().getLowestGainPrice());
assertNull(p1.get().getHighestGainPrice());
assertNull(p1.get().getLatestGainPrice());
// =============================================================================================================
// Creates long position n°2 - 0.0002 ETH bought with BTC.
// Position will be closed if 10 000% gain or 10 000% loss.
final PositionCreationResultDTO position2Result = strategy.createLongPosition(ETH_USDT, new BigDecimal("0.0002"), PositionRulesDTO.builder().stopGainPercentage(10_000f).stopLossPercentage(10_000f).build());
assertEquals("ORDER00020", position2Result.getPosition().getOpeningOrder().getOrderId());
long position2Id = position2Result.getPosition().getUid();
// onPositionStatusUpdate - Position 2 should arrive (OPENING).
// 1 position status update - The position is created with the OPENING status.
await().untilAsserted(() -> assertEquals(2, strategy.getPositionsStatusUpdatesCount()));
p = strategy.getLastPositionStatusUpdate();
assertNotNull(p);
assertEquals(position2Id, p.getUid());
assertEquals(OPENING, p.getStatus());
assertEquals("Long position n°2 of 0.0002 ETH (rules: 10000.0 % gain / 10000.0 % loss) - Opening - Waiting for the trades of order ORDER00020", p.getDescription());
// onPositionUpdate - Position 2 should arrive (OPENING).
// - Position created with a local order saved in database (Order with status PENDING_NEW).
// - Position updated with the local order retrieved from getOrders with status NEW.
await().untilAsserted(() -> assertEquals(4, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position2Id, p.getUid());
assertEquals(OPENING, p.getStatus());
// Check data we have in strategy & database.
assertEquals(2, positionRepository.count());
assertEquals(2, strategy.getPositions().size());
Optional<PositionDTO> p2 = strategy.getPositionByPositionId(position2Id);
assertTrue(p2.isPresent());
assertEquals(2, p2.get().getUid());
assertEquals(2, p2.get().getPositionId());
assertEquals(LONG, p2.get().getType());
assertNotNull(p2.get().getStrategy());
assertEquals(1, p2.get().getStrategy().getUid());
assertEquals("01", p2.get().getStrategy().getStrategyId());
assertEquals(ETH_USDT, p2.get().getCurrencyPair());
assertEquals(0, new BigDecimal("0.0002").compareTo(p2.get().getAmount().getValue()));
assertEquals(ETH_USDT.getBaseCurrency(), p2.get().getAmount().getCurrency());
assertTrue(p2.get().getRules().isStopGainPercentageSet());
assertEquals(10_000f, p2.get().getRules().getStopGainPercentage());
assertTrue(p2.get().getRules().isStopLossPercentageSet());
assertEquals(10_000f, p2.get().getRules().getStopLossPercentage());
assertEquals(OPENING, p2.get().getStatus());
assertEquals("ORDER00020", p2.get().getOpeningOrder().getOrderId());
assertTrue(p2.get().getOpeningOrder().getTrades().isEmpty());
assertNull(p2.get().getClosingOrder());
assertNull(p2.get().getLowestGainPrice());
assertNull(p2.get().getHighestGainPrice());
assertNull(p2.get().getLatestGainPrice());
// =============================================================================================================
// Position n°1 is buying 10 ETH with BTC.
// Two trades arrives with 5 ETH each (so the two makes 10 ETH).
// 11 is before 1 to test the timestamp order of getOpenTrades & getCloseTrades.
// First trade.
tradeFlux.emitValue(TradeDTO.builder().tradeId("000011").type(BID).orderId("ORDER00010").currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("0.02", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("02-02-2020")).build());
// The same trade is emitted two times with an update (on timestamp).
tradeFlux.emitValue(TradeDTO.builder().tradeId("000011").orderId("ORDER00010").type(BID).currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("0.02", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("03-02-2020")).build());
// Second trade.
tradeFlux.emitValue(TradeDTO.builder().tradeId("000001").orderId("ORDER00010").type(BID).currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("0.04", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("01-01-2020")).build());
// The same trade is emitted two times with an update (on timestamp).
tradeFlux.emitValue(TradeDTO.builder().tradeId("000001").orderId("ORDER00010").type(BID).currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("0.04", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("02-01-2020")).build());
// onPositionStatusUpdate - Position 1 should change to OPENED.
// With the two trades emitted, status should change to OPENED.
await().untilAsserted(() -> assertEquals(3, strategy.getPositionsStatusUpdatesCount()));
p = strategy.getLastPositionStatusUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(OPENED, p.getStatus());
assertEquals("Long position n°1 of 10 ETH (rules: 1000.0 % gain / 100.0 % loss) - Opened", p.getDescription());
// onPositionUpdate - 2 trades emitted 2 times so 4 updates (+4 already received for position opening).
// We were at 4 first.
// Trade 000011 arrives with 5 ETH.
// Trade 000011 arrives with timestamp updated.
// Trade 000001 arrives with 5 ETH.
// Trade 000001 arrives with timestamp updated.
// Now we have 8 updates.
await().untilAsserted(() -> assertEquals(8, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(OPENED, p.getStatus());
// Checking what we have in database.
assertEquals(2, strategy.getPositions().size());
p1 = strategy.getPositionByPositionId(position1Uid);
assertTrue(p1.isPresent());
assertEquals(1, p1.get().getUid());
assertEquals(1, p1.get().getPositionId());
assertEquals(LONG, p1.get().getType());
assertNotNull(p1.get().getStrategy());
assertEquals(1, p1.get().getStrategy().getUid());
assertEquals("01", p1.get().getStrategy().getStrategyId());
assertEquals(ETH_BTC, p1.get().getCurrencyPair());
assertEquals(0, new BigDecimal("10").compareTo(p1.get().getAmount().getValue()));
assertEquals(ETH_BTC.getBaseCurrency(), p1.get().getAmount().getCurrency());
assertTrue(p1.get().getRules().isStopGainPercentageSet());
assertEquals(1_000f, p1.get().getRules().getStopGainPercentage());
assertTrue(p1.get().getRules().isStopLossPercentageSet());
assertEquals(100f, p1.get().getRules().getStopLossPercentage());
assertEquals(OPENED, p1.get().getStatus());
assertEquals("ORDER00010", p1.get().getOpeningOrder().getOrderId());
Iterator<TradeDTO> openingTradesIterator = p1.get().getOpeningOrder().getTrades().iterator();
assertEquals("000001", openingTradesIterator.next().getTradeId());
assertEquals("000011", openingTradesIterator.next().getTradeId());
assertNull(p1.get().getClosingOrder());
assertNull(p1.get().getLowestGainPrice());
assertNull(p1.get().getHighestGainPrice());
assertNull(p1.get().getLatestGainPrice());
// Check if we don't have duplicated trades in database !
assertEquals(2, tradeRepository.count());
Optional<Order> order00010 = orderRepository.findByOrderId("ORDER00010");
assertTrue(order00010.isPresent());
assertEquals(2, order00010.get().getTrades().size());
// =============================================================================================================
// Test of tickers updating position n°1.
// From the trades, we had:
// 000011 = 5 * 0.02
// 000001 = 5 * 0.04
// so the price is 0.03.
// First ticker arrives (500% gain) - min, max and last gain should be set to that value.
// Price update so a new position update.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("0.18")).build());
await().untilAsserted(() -> assertEquals(9, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertEquals(position1Uid, p.getUid());
assertEquals(0, new BigDecimal("0.18").compareTo(p.getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.18").compareTo(p.getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.18").compareTo(p.getLatestGainPrice().getValue()));
assertEquals("Long position n°1 of 10 ETH (rules: 1000.0 % gain / 100.0 % loss) - Opened - Last gain calculated 500 %", p.getDescription());
// We check the gain.
Optional<GainDTO> latestCalculatedGain = p.getLatestCalculatedGain();
assertTrue(latestCalculatedGain.isPresent());
assertEquals(500, latestCalculatedGain.get().getPercentage());
assertEquals(0, new BigDecimal("1.5").compareTo(latestCalculatedGain.get().getAmount().getValue()));
assertEquals(BTC, latestCalculatedGain.get().getAmount().getCurrency());
// Second ticker arrives (100% gain) - min and last gain should be set to that value.
// Price update so a new position update.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("0.06")).build());
await().untilAsserted(() -> assertEquals(10, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertEquals(position1Uid, p.getUid());
assertEquals(0, new BigDecimal("0.06").compareTo(p.getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.18").compareTo(p.getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.06").compareTo(p.getLatestGainPrice().getValue()));
// We check the gain.
latestCalculatedGain = p.getLatestCalculatedGain();
assertTrue(latestCalculatedGain.isPresent());
assertEquals(100, latestCalculatedGain.get().getPercentage());
assertEquals(0, new BigDecimal("0.3").compareTo(latestCalculatedGain.get().getAmount().getValue()));
assertEquals(BTC, latestCalculatedGain.get().getAmount().getCurrency());
// Third ticker arrives (200% gain) - only last should change.
// Price update so a new position update.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("0.09")).build());
await().untilAsserted(() -> assertEquals(11, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertEquals(position1Uid, p.getUid());
assertEquals(0, new BigDecimal("0.06").compareTo(p.getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.18").compareTo(p.getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.09").compareTo(p.getLatestGainPrice().getValue()));
// Fourth ticker arrives (50% loss) - min and last gain should be set to that value.
// Price update so a new position update.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("0.015")).build());
await().untilAsserted(() -> assertEquals(12, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertEquals(position1Uid, p.getUid());
assertEquals(0, new BigDecimal("0.015").compareTo(p.getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.18").compareTo(p.getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.015").compareTo(p.getLatestGainPrice().getValue()));
// A ticker arrive for another cp. Nothing should change.
// And no position update.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_USDT).last(new BigDecimal("100")).build());
// Fifth ticker arrives (600% gain) - max and last gain should be set to that value.
// Price update so a new position update.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("0.21")).build());
await().untilAsserted(() -> assertEquals(13, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertEquals(position1Uid, p.getUid());
assertEquals(0, new BigDecimal("0.015").compareTo(p.getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.21").compareTo(p.getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.21").compareTo(p.getLatestGainPrice().getValue()));
// Checking what we have in database.
assertEquals(2, strategy.getPositions().size());
p1 = strategy.getPositionByPositionId(position1Uid);
assertTrue(p1.isPresent());
assertEquals(1, p1.get().getUid());
assertEquals(1, p1.get().getPositionId());
assertEquals(LONG, p1.get().getType());
assertNotNull(p1.get().getStrategy());
assertEquals(1, p1.get().getStrategy().getUid());
assertEquals("01", p1.get().getStrategy().getStrategyId());
assertEquals(ETH_BTC, p1.get().getCurrencyPair());
assertEquals(0, new BigDecimal("10").compareTo(p1.get().getAmount().getValue()));
assertEquals(ETH_BTC.getBaseCurrency(), p1.get().getAmount().getCurrency());
assertTrue(p1.get().getRules().isStopGainPercentageSet());
assertEquals(1_000f, p1.get().getRules().getStopGainPercentage());
assertTrue(p1.get().getRules().isStopLossPercentageSet());
assertEquals(100f, p1.get().getRules().getStopLossPercentage());
assertEquals(OPENED, p1.get().getStatus());
assertEquals("ORDER00010", p1.get().getOpeningOrder().getOrderId());
openingTradesIterator = p1.get().getOpeningOrder().getTrades().iterator();
assertEquals("000001", openingTradesIterator.next().getTradeId());
assertEquals("000011", openingTradesIterator.next().getTradeId());
assertNull(p1.get().getClosingOrder());
assertEquals(0, new BigDecimal("0.015").compareTo(p1.get().getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.21").compareTo(p1.get().getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.21").compareTo(p1.get().getLatestGainPrice().getValue()));
// =============================================================================================================
// Trade arrives for position 2 - should now be OPENED
tradeFlux.emitValue(TradeDTO.builder().tradeId("000002").type(BID).orderId("ORDER00020").currencyPair(ETH_USDT).amount(new CurrencyAmountDTO("0.0002", ETH_USDT.getBaseCurrency())).price(new CurrencyAmountDTO("0.03", ETH_USDT.getQuoteCurrency())).build());
// onPositionStatusUpdate - Position 2 should be opened.
// - Update 1 : position n°1 OPENING.
// - Update 2 : position n°2 OPENING.
// - Update 3 : position n°1 OPENED.
// - Update 4 : position n°2 OPENED.
await().untilAsserted(() -> assertEquals(4, strategy.getPositionsStatusUpdatesCount()));
p = strategy.getLastPositionStatusUpdate();
assertNotNull(p);
assertEquals(position2Id, p.getUid());
assertEquals(OPENED, p.getStatus());
assertEquals("Long position n°2 of 0.0002 ETH (rules: 10000.0 % gain / 10000.0 % loss) - Opened", p.getDescription());
// onPositionUpdate.
// One trade arrives, so we have a position update because of this trade.
await().untilAsserted(() -> assertEquals(14, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position2Id, p.getUid());
assertEquals(OPENED, p.getStatus());
// Checking what we have in database.
assertEquals(2, strategy.getPositions().size());
p2 = strategy.getPositionByPositionId(position2Id);
assertTrue(p2.isPresent());
assertEquals(2, p2.get().getUid());
assertEquals(2, p2.get().getPositionId());
assertEquals(LONG, p2.get().getType());
assertNotNull(p2.get().getStrategy());
assertEquals(1, p2.get().getStrategy().getUid());
assertEquals("01", p2.get().getStrategy().getStrategyId());
assertEquals(ETH_USDT, p2.get().getCurrencyPair());
assertEquals(0, new BigDecimal("0.0002").compareTo(p2.get().getAmount().getValue()));
assertEquals(ETH_USDT.getBaseCurrency(), p2.get().getAmount().getCurrency());
assertTrue(p2.get().getRules().isStopGainPercentageSet());
assertEquals(10_000f, p2.get().getRules().getStopGainPercentage());
assertTrue(p2.get().getRules().isStopLossPercentageSet());
assertEquals(10_000f, p2.get().getRules().getStopLossPercentage());
assertEquals(OPENED, p2.get().getStatus());
assertEquals("ORDER00020", p2.get().getOpeningOrder().getOrderId());
openingTradesIterator = p2.get().getOpeningOrder().getTrades().iterator();
assertEquals("000002", openingTradesIterator.next().getTradeId());
assertNull(p2.get().getClosingOrder());
assertNull(p2.get().getLowestGainPrice());
assertNull(p2.get().getHighestGainPrice());
assertNull(p2.get().getLatestGainPrice());
// =============================================================================================================
// A ticker arrives that triggers max gain rules of position 1 - should now be CLOSING.
// From the trades, we had:
// 000011 = 5 * 0.02
// 000001 = 5 * 0.04
// The mean price is 0.03 BTC, and we now receive a new price of 100.
tickerFlux.emitValue(TickerDTO.builder().currencyPair(ETH_BTC).last(new BigDecimal("100")).build());
// onPositionStatusUpdate - Position 1 should be closing.
// - Update 1 : position n°1 OPENING.
// - Update 2 : position n°2 OPENING.
// - Update 3 : position n°1 OPENED.
// - Update 4 : position n°2 OPENED.
// - Update 5 : position n°1 CLOSING.
await().untilAsserted(() -> assertEquals(5, strategy.getPositionsStatusUpdatesCount()));
p = strategy.getLastPositionStatusUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(CLOSING, p.getStatus());
assertEquals("Long position n°1 of 10 ETH (rules: 1000.0 % gain / 100.0 % loss) - Closing - Waiting for the trades of order ORDER00011", p.getDescription());
// OnPositionUpdate - We were having 14 updates.
// - A ticker triggering position closure arrives.
// - Position closed with the local order (status PENDING_NEW).
// - Position updated with the distant order (status NEW).
await().untilAsserted(() -> assertEquals(17, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(CLOSING, p.getStatus());
// Checking what we have in database.
assertEquals(2, strategy.getPositions().size());
p1 = strategy.getPositionByPositionId(position1Uid);
assertTrue(p1.isPresent());
assertEquals(1, p1.get().getUid());
assertEquals(1, p1.get().getPositionId());
assertEquals(LONG, p1.get().getType());
assertNotNull(p1.get().getStrategy());
assertEquals(1, p1.get().getStrategy().getUid());
assertEquals("01", p1.get().getStrategy().getStrategyId());
assertEquals(ETH_BTC, p1.get().getCurrencyPair());
assertEquals(0, new BigDecimal("10").compareTo(p1.get().getAmount().getValue()));
assertEquals(ETH_BTC.getBaseCurrency(), p1.get().getAmount().getCurrency());
assertTrue(p1.get().getRules().isStopGainPercentageSet());
assertEquals(1_000f, p1.get().getRules().getStopGainPercentage());
assertTrue(p1.get().getRules().isStopLossPercentageSet());
assertEquals(100f, p1.get().getRules().getStopLossPercentage());
assertEquals(CLOSING, p1.get().getStatus());
assertEquals("ORDER00010", p1.get().getOpeningOrder().getOrderId());
openingTradesIterator = p1.get().getOpeningOrder().getTrades().iterator();
assertEquals("000001", openingTradesIterator.next().getTradeId());
assertEquals("000011", openingTradesIterator.next().getTradeId());
assertEquals("ORDER00011", p1.get().getClosingOrder().getOrderId());
assertTrue(p1.get().getClosingOrder().getTrades().isEmpty());
assertEquals(0, new BigDecimal("0.015").compareTo(p1.get().getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.21").compareTo(p1.get().getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("100").compareTo(p1.get().getLatestGainPrice().getValue()));
// =============================================================================================================
// Position 1 will move to CLOSED status when the trades arrive.
// The first close trade arrives but the amount is not enough.
tradeFlux.emitValue(TradeDTO.builder().tradeId("000003").orderId("ORDER00011").type(ASK).currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("1", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("01-01-2020")).build());
// We send a duplicated value.
tradeFlux.emitValue(TradeDTO.builder().tradeId("000003").orderId("ORDER00011").type(ASK).currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("1", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("01-01-2020")).build());
// onPosition for first trade arrival.
// Two new updates : the two trades received (even if they were the same as we use emit method).
await().untilAsserted(() -> assertEquals(19, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(CLOSING, p.getStatus());
// The second close trade arrives now closed.
tradeFlux.emitValue(TradeDTO.builder().tradeId("000004").orderId("ORDER00011").type(ASK).currencyPair(ETH_BTC).amount(new CurrencyAmountDTO("5", ETH_BTC.getBaseCurrency())).price(new CurrencyAmountDTO("1", ETH_BTC.getQuoteCurrency())).timestamp(createZonedDateTime("02-01-2020")).build());
// onPositionStatusUpdate - Position should be closed.
// - Update 1 : position n°1 OPENING.
// - Update 2 : position n°2 OPENING.
// - Update 3 : position n°1 OPENED.
// - Update 4 : position n°2 OPENED.
// - Update 5 : position n°1 CLOSING.
// - Update 6 : position n°1 CLOSED.
await().untilAsserted(() -> assertEquals(6, strategy.getPositionsStatusUpdatesCount()));
p = strategy.getLastPositionStatusUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(CLOSED, p.getStatus());
assertEquals("Long position n°1 of 10 ETH (rules: 1000.0 % gain / 100.0 % loss) - Closed - Gains: 9.7 BTC (3233.33 %)", p.getDescription());
// onPositionUpdate.
// - Trade 000004 arrives.
await().untilAsserted(() -> assertEquals(20, strategy.getPositionsUpdatesCount()));
p = strategy.getLastPositionUpdate();
assertNotNull(p);
assertEquals(position1Uid, p.getUid());
assertEquals(CLOSED, p.getStatus());
// Checking what we have in database.
assertEquals(2, strategy.getPositions().size());
p1 = strategy.getPositionByPositionId(position1Uid);
assertTrue(p1.isPresent());
assertEquals(1, p1.get().getUid());
assertEquals(1, p1.get().getPositionId());
assertEquals(LONG, p1.get().getType());
assertNotNull(p1.get().getStrategy());
assertEquals(1, p1.get().getStrategy().getUid());
assertEquals("01", p1.get().getStrategy().getStrategyId());
assertEquals(ETH_BTC, p1.get().getCurrencyPair());
assertEquals(0, new BigDecimal("10").compareTo(p1.get().getAmount().getValue()));
assertEquals(ETH_BTC.getBaseCurrency(), p1.get().getAmount().getCurrency());
assertTrue(p1.get().getRules().isStopGainPercentageSet());
assertEquals(1_000f, p1.get().getRules().getStopGainPercentage());
assertTrue(p1.get().getRules().isStopLossPercentageSet());
assertEquals(100f, p1.get().getRules().getStopLossPercentage());
assertEquals(CLOSED, p1.get().getStatus());
assertEquals("ORDER00010", p1.get().getOpeningOrder().getOrderId());
openingTradesIterator = p1.get().getOpeningOrder().getTrades().iterator();
assertEquals("000001", openingTradesIterator.next().getTradeId());
assertEquals("000011", openingTradesIterator.next().getTradeId());
assertEquals("ORDER00011", p1.get().getClosingOrder().getOrderId());
final Iterator<TradeDTO> closingTradesIterator = p1.get().getClosingOrder().getTrades().iterator();
assertEquals("000003", closingTradesIterator.next().getTradeId());
assertEquals("000004", closingTradesIterator.next().getTradeId());
assertEquals(0, new BigDecimal("0.015").compareTo(p1.get().getLowestGainPrice().getValue()));
assertEquals(0, new BigDecimal("0.21").compareTo(p1.get().getHighestGainPrice().getValue()));
assertEquals(0, new BigDecimal("100").compareTo(p1.get().getLatestGainPrice().getValue()));
// Just checking trades creation.
assertNotNull(strategy.getPositionByPositionId(position1Uid));
assertNotNull(strategy.getPositionByPositionId(position2Id));
assertEquals(5, strategy.getTrades().size());
// Check if we don't have duplicated trades in database !
assertEquals(5, tradeRepository.count());
order00010 = orderRepository.findByOrderId("ORDER00010");
assertTrue(order00010.isPresent());
assertEquals(2, order00010.get().getTrades().size());
final Optional<Order> order00011 = orderRepository.findByOrderId("ORDER00011");
assertTrue(order00011.isPresent());
assertEquals(2, order00011.get().getTrades().size());
}
use of tech.cassandre.trading.bot.dto.util.GainDTO in project cassandre-trading-bot by cassandre-tech.
the class PositionServiceCassandreImplementation method getGains.
@Override
public final Map<CurrencyDTO, GainDTO> getGains(final long strategyUid) {
logger.debug("Retrieving gains for all positions");
HashMap<CurrencyDTO, BigDecimal> totalBefore = new LinkedHashMap<>();
HashMap<CurrencyDTO, BigDecimal> totalAfter = new LinkedHashMap<>();
List<CurrencyAmountDTO> openingOrdersFees = new LinkedList<>();
List<CurrencyAmountDTO> closingOrdersFees = new LinkedList<>();
HashMap<CurrencyDTO, GainDTO> gains = new LinkedHashMap<>();
// We calculate, by currency, the amount bought & sold.
positionRepository.findByStatus(CLOSED).stream().filter(position -> strategyUid == 0 || position.getStrategy().getUid() == strategyUid).map(POSITION_MAPPER::mapToPositionDTO).forEach(positionDTO -> {
// We retrieve the currency and initiate the maps if they are empty
CurrencyDTO currency;
if (positionDTO.getType() == LONG) {
// LONG.
currency = positionDTO.getCurrencyPair().getQuoteCurrency();
} else {
// SHORT.
currency = positionDTO.getCurrencyPair().getBaseCurrency();
}
gains.putIfAbsent(currency, null);
totalBefore.putIfAbsent(currency, ZERO);
totalAfter.putIfAbsent(currency, ZERO);
// We calculate the amounts bought and amount sold.
if (positionDTO.getType() == LONG) {
totalBefore.put(currency, positionDTO.getOpeningOrder().getTrades().stream().map(t -> t.getAmountValue().multiply(t.getPriceValue())).reduce(totalBefore.get(currency), BigDecimal::add));
totalAfter.put(currency, positionDTO.getClosingOrder().getTrades().stream().map(t -> t.getAmountValue().multiply(t.getPriceValue())).reduce(totalAfter.get(currency), BigDecimal::add));
} else {
totalBefore.put(currency, positionDTO.getOpeningOrder().getTrades().stream().map(TradeDTO::getAmountValue).reduce(totalBefore.get(currency), BigDecimal::add));
totalAfter.put(currency, positionDTO.getClosingOrder().getTrades().stream().map(TradeDTO::getAmountValue).reduce(totalAfter.get(currency), BigDecimal::add));
}
// And now the fees.
positionDTO.getOpeningOrder().getTrades().stream().filter(tradeDTO -> tradeDTO.getFee() != null).forEach(tradeDTO -> openingOrdersFees.add(tradeDTO.getFee()));
positionDTO.getClosingOrder().getTrades().stream().filter(tradeDTO -> tradeDTO.getFee() != null).forEach(tradeDTO -> closingOrdersFees.add(tradeDTO.getFee()));
});
gains.keySet().forEach(currency -> {
// We make the calculation.
BigDecimal before = totalBefore.get(currency);
BigDecimal after = totalAfter.get(currency);
BigDecimal gainAmount = after.subtract(before);
BigDecimal gainPercentage = ((after.subtract(before)).divide(before, HALF_UP)).multiply(ONE_HUNDRED_BIG_DECIMAL);
GainDTO g = GainDTO.builder().percentage(gainPercentage.setScale(2, HALF_UP).doubleValue()).amount(CurrencyAmountDTO.builder().value(gainAmount).currency(currency).build()).openingOrderFees(openingOrdersFees).closingOrderFees(closingOrdersFees).build();
gains.put(currency, g);
});
return gains;
}
Aggregations