use of tech.cassandre.trading.bot.dto.user.AccountDTO in project cassandre-trading-bot by cassandre-tech.
the class AccountDTOTest method checkEqualToForBalancesList.
@Test
@DisplayName("Check equals() on balances list")
public void checkEqualToForBalancesList() {
Set<BalanceDTO> balances = new LinkedHashSet<>();
// Account 1 - No balances.
AccountDTO account1 = AccountDTO.builder().balances(balances).build();
// Account 2 - One more balance in account 1.
balances.add(BalanceDTO.builder().build());
AccountDTO account2 = AccountDTO.builder().balances(balances).build();
balances.clear();
assertNotEquals(account1, account2);
assertNotEquals(account2, account1);
// Account 3 - One ETH & one BTC.
balances.add(BalanceDTO.builder().currency(ETH).build());
balances.add(BalanceDTO.builder().currency(BTC).build());
AccountDTO account3 = AccountDTO.builder().balances(balances).build();
balances.clear();
// Account 4 - One BTC & one ETH (inverted compared to account 3).
balances.add(BalanceDTO.builder().currency(BTC).build());
balances.add(BalanceDTO.builder().currency(ETH).build());
AccountDTO account4 = AccountDTO.builder().balances(balances).build();
balances.clear();
assertEquals(account3, account4);
assertEquals(account4, account3);
// Account 5 - One BTC & one USDT (inverted).
balances.add(BalanceDTO.builder().currency(BTC).build());
balances.add(BalanceDTO.builder().currency(USDT).build());
AccountDTO account5 = AccountDTO.builder().balances(balances).build();
balances.clear();
assertNotEquals(account4, account5);
assertNotEquals(account5, account4);
}
use of tech.cassandre.trading.bot.dto.user.AccountDTO in project cassandre-trading-bot by cassandre-tech.
the class TradeServiceDryModeAOP method createBuyMarketOrder.
@Around(value = "execution(* tech.cassandre.trading.bot.service.TradeService.createBuyMarketOrder(..)) && args(strategy, currencyPair, amount)", argNames = "pjp, strategy, currencyPair, amount")
public final OrderCreationResultDTO createBuyMarketOrder(final ProceedingJoinPoint pjp, final CassandreStrategy strategy, final CurrencyPairDTO currencyPair, final BigDecimal amount) {
// We check that we have the trade account.
final Optional<AccountDTO> tradeAccount = strategy.getTradeAccount();
if (tradeAccount.isEmpty()) {
throw new DryModeException("Trade account was not found");
}
// We check if we have enough assets to buy.
// Buying order - we buy ETH with BTC.
// We are buying the following amount: ticker last price * amount
Optional<BalanceDTO> balance = tradeAccount.get().getBalance(currencyPair.getQuoteCurrency());
final Optional<TickerDTO> ticker = strategy.getLastTickerByCurrencyPair(currencyPair);
if (balance.isPresent() && ticker.isPresent()) {
BigDecimal ownedAssets = balance.get().getAvailable();
BigDecimal cost = ticker.get().getLast().multiply(amount);
if (cost.compareTo(ownedAssets) > 0) {
final String errorMessage = "Not enough assets (costs: " + cost + " " + currencyPair.getQuoteCurrency() + " - owned assets: " + ownedAssets + " " + currencyPair.getQuoteCurrency() + ")";
return new OrderCreationResultDTO(errorMessage, new RuntimeException());
}
} else {
return new OrderCreationResultDTO("No assets (" + currencyPair.getQuoteCurrency() + ")", new RuntimeException());
}
// We execute the buy.
Object result = null;
try {
result = pjp.proceed();
} catch (Throwable throwable) {
logger.error("Error in Dry mode AOP: {}", throwable.getMessage());
}
// We update the account.
userService.addToBalance(strategy, CURRENCY_MAPPER.mapToCurrency(currencyPair.getBaseCurrency()), amount);
userService.addToBalance(strategy, CURRENCY_MAPPER.mapToCurrency(currencyPair.getQuoteCurrency()), amount.multiply(ticker.get().getLast()).multiply(new BigDecimal("-1")));
return (OrderCreationResultDTO) result;
}
use of tech.cassandre.trading.bot.dto.user.AccountDTO in project cassandre-trading-bot by cassandre-tech.
the class UserServiceDryModeAOP method addToBalance.
/**
* Update balance of trade account (method called by trade service).
*
* @param strategy strategy
* @param currency currency
* @param amount amount
*/
public void addToBalance(final CassandreStrategy strategy, final Currency currency, final BigDecimal amount) {
final Optional<AccountDTO> tradeAccount = strategy.getTradeAccount();
if (tradeAccount.isEmpty()) {
logger.error("Trading account not found!");
} else {
// We build a new account information from what we saved.
Collection<Wallet> wallets = new LinkedHashSet<>();
// We retreat all the wallets we have.
accountInfo.getWallets().forEach((name, wallet) -> {
HashMap<Currency, Balance> balances = new LinkedHashMap<>();
// For each balance, we add it if nothing changed or, if on trading account, and we need to change the amount,
// Then we do it.
wallet.getBalances().forEach((balanceCurrency, balance) -> {
if (name.equals(tradeAccount.get().getName()) && balanceCurrency.equals(currency)) {
// If we are on the account and currency to update, we calculate the new value.
balances.put(balanceCurrency, new Balance(balanceCurrency, balance.getTotal().add(amount)));
} else {
// Else we keep the same value.
balances.put(balanceCurrency, balance);
}
});
// amounts, then we create a new balance.
if (name.equals(tradeAccount.get().getName()) && balances.get(currency) == null) {
balances.put(currency, new Balance(currency, amount));
}
// We add the wallet.
wallets.add(new Wallet(name, name, balances.values(), Collections.emptySet(), ZERO, ZERO));
});
// Creates the account info.
accountInfo = new AccountInfo(USER_ID, wallets);
// Updates all strategies.
final UserDTO userDTO = ACCOUNT_MAPPER.mapToUserDTO(accountInfo);
applicationContext.getBeansWithAnnotation(tech.cassandre.trading.bot.strategy.CassandreStrategy.class).values().stream().map(o -> (CassandreStrategyInterface) o).forEach(cassandreStrategyInterface -> cassandreStrategyInterface.initializeAccounts(userDTO.getAccounts()));
}
}
use of tech.cassandre.trading.bot.dto.user.AccountDTO in project cassandre-trading-bot by cassandre-tech.
the class BasicCassandreStrategyTest method checkStrategyBehavior.
@Test
@DisplayName("Check strategy behavior")
public void checkStrategyBehavior() {
// =============================================================================================================
// We check that the strategy is correctly registered in database.
Optional<Strategy> strategyInDatabase = strategyRepository.findByStrategyId("01");
assertTrue(strategyInDatabase.isPresent());
assertEquals(1, strategyInDatabase.get().getUid());
assertEquals("01", strategyInDatabase.get().getStrategyId());
assertEquals("Testable strategy", strategyInDatabase.get().getName());
// =============================================================================================================
// We check accounts updates (4 replies : account 01, account 02, account 03 and again account 03).
// But the 4 replies only concerns 3 account.
// We have 1 BTC, 10 ETH and 100 USDT.
with().await().untilAsserted(() -> assertEquals(4, strategy.getAccountsUpdatesReceived().size()));
assertEquals(3, strategy.getAccounts().size());
// Testing trade account.
final Optional<AccountDTO> tradeAccount = strategy.getTradeAccount();
assertTrue(tradeAccount.isPresent());
assertEquals("03", tradeAccount.get().getAccountId());
assertEquals("trade", tradeAccount.get().getName());
// Testing trade account balances.
assertEquals(3, strategy.getTradeAccountBalances().size());
assertEquals(0, new BigDecimal("1").compareTo(strategy.getTradeAccountBalances().get(BTC).getAvailable()));
assertEquals(0, new BigDecimal("10").compareTo(strategy.getTradeAccountBalances().get(ETH).getAvailable()));
assertEquals(0, new BigDecimal("100").compareTo(strategy.getTradeAccountBalances().get(USDT).getAvailable()));
// =============================================================================================================
// We check that all tickers arrived (6 ETH/BTC & 1 ETH/USDT).
// 1 ETH = 6 BTC.
// 1 ETH = 10 000 USDT.
with().await().untilAsserted(() -> assertEquals(7, strategy.getTickersUpdatesReceived().size()));
assertEquals(2, strategy.getLastTickers().size());
assertNotNull(strategy.getLastTickers().get(ETH_BTC));
assertNotNull(strategy.getLastTickers().get(ETH_USDT));
assertEquals(0, new BigDecimal("6").compareTo(strategy.getLastTickers().get(ETH_BTC).getLast()));
assertEquals(0, new BigDecimal("10000").compareTo(strategy.getLastTickers().get(ETH_USDT).getLast()));
// =============================================================================================================
// Check getEstimatedBuyingCost().
// As 1 ETH cost 6 BTC, 2 ETH would cost 12 BTC.
final Optional<CurrencyAmountDTO> estimatedBuyingCost = strategy.getEstimatedBuyingCost(ETH_BTC, new BigDecimal(2));
assertTrue(estimatedBuyingCost.isPresent());
assertEquals(0, new BigDecimal("12").compareTo(estimatedBuyingCost.get().getValue()));
// =============================================================================================================
// Check getEstimatedBuyableAmount()
// As 1 ETH cost 10 000 USDT, with 5 000 USDT, I should be able to buy 0.5 ETH.
// And I check I can't 260 EUR with ETH as I don't have EURO price.
// And I check I can't buy USDT with EURO as I don't have EURO.
final Optional<BigDecimal> estimatedBuyableAmount = strategy.getEstimatedBuyableAmount(new CurrencyAmountDTO(new BigDecimal(5000), USDT), ETH);
assertTrue(estimatedBuyableAmount.isPresent());
assertEquals(0, new BigDecimal("0.5").compareTo(estimatedBuyableAmount.get()));
assertFalse(strategy.getEstimatedBuyableAmount(new CurrencyAmountDTO(new BigDecimal(260), EUR), ETH).isPresent());
assertFalse(strategy.getEstimatedBuyableAmount(new CurrencyAmountDTO(new BigDecimal(260), USDT), EUR).isPresent());
// =============================================================================================================
// Check canBuy() & canSell().
// Our assets: we have 1 BTC, 10 ETH and 100 USDT.
// 1 ETH costs 6 BTC.
// 1 ETH costs 10 000 USDT.
final AccountDTO account = strategy.getAccounts().get("03");
assertNotNull(account);
// canBuy().
// Buying something for an asset we don't have.
assertFalse(strategy.canBuy(BTC_ETH, new BigDecimal("0.00001")));
assertFalse(strategy.canBuy(account, BTC_ETH, new BigDecimal("0.00001")));
// Trying to buy a full bitcoin, but we only have 2 000 USDT.
assertFalse(strategy.canBuy(ETH_USDT, new BigDecimal("1")));
assertFalse(strategy.canBuy(account, ETH_USDT, new BigDecimal("1")));
// Trying to buy a 0.01 ETH that will cost 100 USDT, and we have 100 USDT, it should work but not for 0.011.
assertTrue(strategy.canBuy(ETH_USDT, new BigDecimal("0.01")));
assertTrue(strategy.canBuy(account, ETH_USDT, new BigDecimal("0.01")));
assertFalse(strategy.canBuy(account, ETH_USDT, new BigDecimal("0.011")));
// Trying to buy a 0.01 bitcoin that costs 100 USDT (we have 100 USDT). But we want to have 1 USDT left.
assertFalse(strategy.canBuy(ETH_USDT, new BigDecimal("0.01"), new BigDecimal("1")));
assertFalse(strategy.canBuy(ETH_USDT, new BigDecimal("0.01"), new BigDecimal("1")));
assertFalse(strategy.canBuy(account, ETH_USDT, new BigDecimal("0.01"), new BigDecimal("1")));
assertFalse(strategy.canBuy(account, ETH_USDT, new BigDecimal("0.01"), new BigDecimal("1")));
// canSell().
// Selling an asset we don't have (EUR).
assertFalse(strategy.canSell(EUR, new BigDecimal("0.00001")));
assertFalse(strategy.canSell(account, EUR, new BigDecimal("0.00001")));
// Trying to sell 1 BTC (we have them).
assertTrue(strategy.canSell(BTC, new BigDecimal("1")));
assertTrue(strategy.canSell(account, BTC, new BigDecimal("1")));
// Trying to sell 3 BTC (we don't have them).
assertFalse(strategy.canSell(BTC, new BigDecimal("3")));
assertFalse(strategy.canSell(account, BTC, new BigDecimal("3")));
// Trying to sell 1 BTC and still have 1 (not possible).
assertFalse(strategy.canSell(BTC, new BigDecimal("1"), new BigDecimal("1")));
assertFalse(strategy.canSell(account, BTC, new BigDecimal("1"), new BigDecimal("1")));
}
use of tech.cassandre.trading.bot.dto.user.AccountDTO in project cassandre-trading-bot by cassandre-tech.
the class BasicCassandreStrategyTestMock method userService.
@SuppressWarnings("unchecked")
@Bean
@Primary
public UserService userService() {
Set<BalanceDTO> balances = new LinkedHashSet<>();
final Map<String, AccountDTO> accounts = new LinkedHashMap<>();
UserService userService = mock(UserService.class);
// =============================================================================================================
// Account retrieved by configuration - Empty, just allowing the getTradeAccount() in configuration to work.
AccountDTO tempAccount = AccountDTO.builder().accountId("03").name("trade").build();
accounts.put("03", tempAccount);
UserDTO tempUser = UserDTO.builder().accounts(accounts).build();
accounts.clear();
// =============================================================================================================
// Creating the response to the first call of the AccountFlux.
// User has three accounts:
// - Account 01 (No name with 1 BTC).
// - Account 02 (No name with 1 ETH).
// - Account 03 (Trade account with 2 BTC, 10 ETH, 2 000 USDT).
// User service response 01.
BalanceDTO account01Balance1 = BalanceDTO.builder().currency(BTC).available(new BigDecimal("1")).build();
balances.add(account01Balance1);
AccountDTO account01 = AccountDTO.builder().accountId("01").balances(balances).build();
accounts.put("01", account01);
UserDTO userResponse01 = UserDTO.builder().accounts(accounts).build();
balances.clear();
accounts.clear();
// User service response 02.
BalanceDTO account02Balance1 = BalanceDTO.builder().currency(ETH).available(new BigDecimal("1")).build();
balances.add(account02Balance1);
AccountDTO account02 = AccountDTO.builder().accountId("02").balances(balances).build();
accounts.put("02", account02);
UserDTO userResponse02 = UserDTO.builder().accounts(accounts).build();
balances.clear();
accounts.clear();
// User service response 03.
balances.add(BalanceDTO.builder().currency(BTC).available(new BigDecimal("2")).build());
balances.add(BalanceDTO.builder().currency(ETH).available(new BigDecimal("10")).build());
balances.add(BalanceDTO.builder().currency(EUR).available(new BigDecimal("2000")).build());
AccountDTO account03 = AccountDTO.builder().accountId("03").name("trade").balances(balances).build();
accounts.put("03", account03);
UserDTO userResponse03 = UserDTO.builder().accounts(accounts).build();
balances.clear();
accounts.clear();
// User service response 04.
balances.add(BalanceDTO.builder().currency(BTC).available(new BigDecimal("1")).build());
balances.add(BalanceDTO.builder().currency(ETH).available(new BigDecimal("10")).build());
balances.add(BalanceDTO.builder().currency(USDT).available(new BigDecimal("100")).build());
AccountDTO account04 = AccountDTO.builder().accountId("03").name("trade").balances(balances).build();
accounts.put("03", account04);
UserDTO userResponse04 = UserDTO.builder().accounts(accounts).build();
balances.clear();
accounts.clear();
// We have two different mock replies.
// StrategiesAutoConfiguration calls userService.getUser().
given(userService.getUser()).willReturn(Optional.of(tempUser));
// AccountFlux calls userService.getAccounts()
given(userService.getAccounts()).willReturn(userResponse01.getAccounts(), userResponse02.getAccounts(), userResponse03.getAccounts(), userResponse04.getAccounts());
return userService;
}
Aggregations