use of com.github.robozonky.api.strategies.LoanDescriptor in project robozonky by RoboZonky.
the class StaticInvestorTest method investmentFromAmountlessConfirmation.
@Test
void investmentFromAmountlessConfirmation() {
final LoanDescriptor ld = mockLoanDescriptor();
final int recommended = 200;
final Investment i = Investor.convertToInvestment(ld.recommend(recommended).get());
assertThat(i.getOriginalPrincipal().intValue()).isEqualTo(recommended);
}
use of com.github.robozonky.api.strategies.LoanDescriptor in project robozonky by RoboZonky.
the class StrategyExecutorTest method rechecksMarketplaceIfBalanceIncreased.
@Test
void rechecksMarketplaceIfBalanceIncreased() {
final Zonky zonky = harmlessZonky(10_000);
final Portfolio p = Portfolio.create(zonky, mockBalance(zonky));
final Loan loan = Loan.custom().build();
final LoanDescriptor ld = new LoanDescriptor(loan);
final Collection<LoanDescriptor> marketplace = Collections.singleton(ld);
// prepare the executor, have it fail when executing the investment operation
final StrategyExecutor<LoanDescriptor, InvestmentStrategy> e = new AlwaysFreshNeverInvesting();
final StrategyExecutor<LoanDescriptor, InvestmentStrategy> mocked = spy(e);
// marketplace never has any updates
when(mocked.hasMarketplaceUpdates(any())).thenReturn(false);
// fresh balance, check marketplace
mocked.apply(p, marketplace);
verify(mocked).execute(eq(p), eq(ALL_ACCEPTING_STRATEGY), eq(marketplace));
// nothing changed, still only ran once
mocked.apply(p, marketplace);
verify(mocked, times(1)).execute(eq(p), eq(ALL_ACCEPTING_STRATEGY), eq(marketplace));
// increase remote balance
when(zonky.getWallet()).thenReturn(new Wallet(BigDecimal.valueOf(100_000)));
// should have checked marketplace
mocked.apply(p, marketplace);
verify(mocked, times(2)).execute(eq(p), eq(ALL_ACCEPTING_STRATEGY), eq(marketplace));
}
use of com.github.robozonky.api.strategies.LoanDescriptor in project robozonky by RoboZonky.
the class InvestingDaemon method execute.
@Override
protected void execute(final Portfolio portfolio, final Authenticated authenticated) {
// don't query anything unless we have enough money to invest
final int balance = portfolio.getRemoteBalance().get().intValue();
final int minimum = Defaults.MINIMUM_INVESTMENT_IN_CZK;
if (balance < minimum) {
LOGGER.debug("Asleep as there is not enough available balance. ({} < {})", balance, minimum);
return;
}
// query marketplace for investment opportunities
final Collection<LoanDescriptor> loans = authenticated.call(zonky -> zonky.getAvailableLoans(SELECT)).parallel().filter(// re-investing would fail
l -> !l.getMyInvestment().isPresent()).map(l -> {
/*
* Loan is first retrieved from the authenticated API. This way, we get all available
* information, such as borrower nicknames from other loans made by the same person.
*/
final Loan complete = authenticated.call(zonky -> LoanCache.INSTANCE.getLoan(l.getId(), zonky));
/*
* We update the loan within the cache with latest information from the marketplace. This is
* done so that we don't cache stale loan information, such as how much of the loan is remaining
* to be invested.
*/
Loan.updateFromMarketplace(complete, l);
return complete;
}).map(LoanDescriptor::new).collect(Collectors.toList());
investing.apply(portfolio, loans);
}
use of com.github.robozonky.api.strategies.LoanDescriptor in project robozonky by RoboZonky.
the class Investing method hasMarketplaceUpdates.
@Override
protected boolean hasMarketplaceUpdates(final Collection<LoanDescriptor> marketplace) {
final OffsetDateTime now = OffsetDateTime.now();
final int[] actionableLoansNow = marketplace.stream().filter(l -> l.getLoanCaptchaProtectionEndDateTime().map(d -> d.isBefore(now)).orElse(true)).mapToInt(l -> l.item().getId()).toArray();
final int[] lastCheckedActionableLoans = actionableWhenLastChecked.getAndSet(actionableLoansNow);
return StrategyExecutor.hasNewIds(lastCheckedActionableLoans, actionableLoansNow);
}
use of com.github.robozonky.api.strategies.LoanDescriptor in project robozonky by RoboZonky.
the class EmailingListenerTest method listeners.
@TestFactory
Stream<DynamicNode> listeners() throws MalformedURLException {
// prepare data
final Loan loan = Loan.custom().setId(66666).setAmount(100_000).setInterestRate(BigDecimal.TEN).setDatePublished(OffsetDateTime.now().minusMonths(2)).setName("Úvěr").setRegion(Region.JIHOCESKY).setPurpose(Purpose.AUTO_MOTO).setMainIncomeType(MainIncomeType.EMPLOYMENT).setRemainingInvestment(2000).setRating(Rating.AAAAA).setTermInMonths(25).setUrl(new URL("http://www.robozonky.cz")).build();
final LoanDescriptor loanDescriptor = new LoanDescriptor(loan);
final RecommendedLoan recommendation = loanDescriptor.recommend(1200, false).get();
final Investment i = Investment.fresh((MarketplaceLoan) loan, 1000).build();
// create events for listeners
return Stream.of(forListener(SupportedListener.INVESTMENT_DELEGATED, new InvestmentDelegatedEvent(recommendation, "random")), forListener(SupportedListener.INVESTMENT_MADE, new InvestmentMadeEvent(i, loan, MAX_PORTFOLIO)), forListener(SupportedListener.INVESTMENT_SOLD, new InvestmentSoldEvent(i, loan, MAX_PORTFOLIO)), forListener(SupportedListener.INVESTMENT_SKIPPED, new InvestmentSkippedEvent(recommendation)), forListener(SupportedListener.INVESTMENT_REJECTED, new InvestmentRejectedEvent(recommendation, "random")), forListener(SupportedListener.LOAN_NO_LONGER_DELINQUENT, new LoanNoLongerDelinquentEvent(i, loan, LocalDate.now(), Collections.singletonList(mockCollectionNoEndDate()))), forListener(SupportedListener.LOAN_DEFAULTED, new LoanDefaultedEvent(i, loan, LocalDate.now(), Collections.singletonList(mockCollectionNoNote()))), forListener(SupportedListener.LOAN_NOW_DELINQUENT, new LoanNowDelinquentEvent(i, loan, LocalDate.now(), Collections.emptyList())), forListener(SupportedListener.LOAN_DELINQUENT_10_PLUS, new LoanDelinquent10DaysOrMoreEvent(i, loan, LocalDate.now().minusDays(11), Collections.emptyList())), forListener(SupportedListener.LOAN_DELINQUENT_30_PLUS, new LoanDelinquent30DaysOrMoreEvent(i, loan, LocalDate.now().minusDays(31), Collections.emptyList())), forListener(SupportedListener.LOAN_DELINQUENT_60_PLUS, new LoanDelinquent60DaysOrMoreEvent(i, loan, LocalDate.now().minusDays(61), Collections.emptyList())), forListener(SupportedListener.LOAN_DELINQUENT_90_PLUS, new LoanDelinquent90DaysOrMoreEvent(i, loan, LocalDate.now().minusDays(91), Collections.emptyList())), forListener(SupportedListener.LOAN_REPAID, new LoanRepaidEvent(i, loan, MAX_PORTFOLIO)), forListener(SupportedListener.BALANCE_ON_TARGET, new ExecutionStartedEvent(Collections.emptyList(), MAX_PORTFOLIO)), forListener(SupportedListener.BALANCE_UNDER_MINIMUM, new ExecutionStartedEvent(Collections.emptyList(), mockPortfolio(0))), forListener(SupportedListener.CRASHED, new RoboZonkyCrashedEvent(ReturnCode.ERROR_UNEXPECTED, new RuntimeException())), forListener(SupportedListener.REMOTE_OPERATION_FAILED, new RemoteOperationFailedEvent(new RuntimeException())), forListener(SupportedListener.DAEMON_FAILED, new RoboZonkyDaemonFailedEvent(new RuntimeException())), forListener(SupportedListener.INITIALIZED, new RoboZonkyInitializedEvent()), forListener(SupportedListener.ENDING, new RoboZonkyEndingEvent()), forListener(SupportedListener.TESTING, new RoboZonkyTestingEvent()), forListener(SupportedListener.UPDATE_DETECTED, new RoboZonkyUpdateDetectedEvent("1.2.3")), forListener(SupportedListener.EXPERIMENTAL_UPDATE_DETECTED, new RoboZonkyExperimentalUpdateDetectedEvent("1.3.0-beta-1")), forListener(SupportedListener.INVESTMENT_PURCHASED, new InvestmentPurchasedEvent(i, loan, MAX_PORTFOLIO)), forListener(SupportedListener.SALE_OFFERED, new SaleOfferedEvent(i, loan)));
}
Aggregations