use of com.github.robozonky.api.remote.entities.sanitized.Investment 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)));
}
use of com.github.robozonky.api.remote.entities.sanitized.Investment in project robozonky by RoboZonky.
the class ParsedStrategyTest method exitButNoSelloff.
@Test
void exitButNoSelloff() {
final DefaultPortfolio portfolio = DefaultPortfolio.EMPTY;
final DefaultValues values = new DefaultValues(portfolio);
// exit active, no sell-off yet
values.setExitProperties(new ExitProperties(LocalDate.now().plusMonths(6)));
final ParsedStrategy strategy = new ParsedStrategy(values, Collections.emptyList(), Collections.emptyMap(), new FilterSupplier(values, Collections.emptySet(), Collections.emptySet(), Collections.emptySet()));
// no loan or participation should be bought; every investment should be sold
final Loan loanUnder = mockLoan(1000);
final Loan loanOver = Loan.custom().setId(2).setAmount(2000).setTermInMonths(84).build();
final LoanDescriptor ldOver = new LoanDescriptor(loanOver);
final LoanDescriptor ldUnder = new LoanDescriptor(loanUnder);
final ParticipationDescriptor pdOver = mockParticipationDescriptor(loanOver);
final ParticipationDescriptor pdUnder = mockParticipationDescriptor(loanUnder);
final Investment iUnder = Investment.fresh((MarketplaceLoan) loanUnder, 200);
final InvestmentDescriptor idUnder = new InvestmentDescriptor(iUnder, loanUnder);
final Investment iOver = Investment.fresh((MarketplaceLoan) loanOver, 200);
final InvestmentDescriptor idOver = new InvestmentDescriptor(iOver, loanOver);
assertSoftly(softly -> {
softly.assertThat(strategy.getApplicableLoans(Arrays.asList(ldOver, ldUnder))).containsOnly(ldUnder);
softly.assertThat(strategy.getApplicableParticipations(Arrays.asList(pdOver, pdUnder))).containsOnly(pdUnder);
softly.assertThat(strategy.getApplicableInvestments(Arrays.asList(idOver, idUnder))).isEmpty();
});
}
use of com.github.robozonky.api.remote.entities.sanitized.Investment in project robozonky by RoboZonky.
the class Selling method processInvestment.
private Optional<Investment> processInvestment(final Zonky zonky, final RecommendedInvestment r) {
Events.fire(new SaleRequestedEvent(r));
final Investment i = r.descriptor().item();
if (isDryRun) {
LOGGER.debug("Not sending sell request for loan #{} due to dry run.", i.getLoanId());
} else {
LOGGER.debug("Sending sell request for loan #{}.", i.getLoanId());
zonky.sell(i);
LOGGER.trace("Request over.");
}
Investment.putOnSmp(i);
Events.fire(new SaleOfferedEvent(i, r.descriptor().related()));
return Optional.of(i);
}
use of com.github.robozonky.api.remote.entities.sanitized.Investment in project robozonky by RoboZonky.
the class Selling method sell.
private void sell(final Portfolio portfolio, final SellStrategy strategy, final Authenticated auth) {
final PortfolioOverview overview = portfolio.calculateOverview();
final Set<InvestmentDescriptor> eligible = portfolio.getActiveForSecondaryMarketplace().parallel().map(i -> getDescriptor(i, auth)).collect(Collectors.toSet());
Events.fire(new SellingStartedEvent(eligible, overview));
final Collection<Investment> investmentsSold = strategy.recommend(eligible, overview).peek(r -> Events.fire(new SaleRecommendedEvent(r))).map(r -> auth.call(zonky -> processInvestment(zonky, r))).flatMap(o -> o.map(Stream::of).orElse(Stream.empty())).collect(Collectors.toSet());
Events.fire(new SellingCompletedEvent(investmentsSold, portfolio.calculateOverview()));
}
use of com.github.robozonky.api.remote.entities.sanitized.Investment in project robozonky by RoboZonky.
the class Session method invest.
/**
* Request {@link ControlApi} to invest in a given loan, leveraging the {@link ConfirmationProvider}.
* @param recommendation Loan to invest into.
* @return True if investment successful. The investment is reflected in {@link #getResult()}.
*/
public boolean invest(final RecommendedLoan recommendation) {
final LoanDescriptor loan = recommendation.descriptor();
final int loanId = loan.item().getId();
if (portfolioOverview.getCzkAvailable() < recommendation.amount().intValue()) {
// should not be allowed by the calling code
return false;
}
Events.fire(new InvestmentRequestedEvent(recommendation));
final boolean seenBefore = state.getSeenLoans().stream().anyMatch(l -> isSameLoan(l, loanId));
final ZonkyResponse response = investor.invest(recommendation, seenBefore);
Session.LOGGER.debug("Response for loan {}: {}.", loanId, response);
final String providerId = investor.getConfirmationProviderId().orElse("-");
switch(response.getType()) {
case REJECTED:
return investor.getConfirmationProviderId().map(c -> {
Events.fire(new InvestmentRejectedEvent(recommendation, providerId));
// rejected through a confirmation provider => forget
discard(loan);
return false;
}).orElseGet(() -> {
// rejected due to no confirmation provider => make available for direct investment later
Events.fire(new InvestmentSkippedEvent(recommendation));
Session.LOGGER.debug("Loan #{} protected by CAPTCHA, will check back later.", loanId);
skip(loan);
return false;
});
case DELEGATED:
final Event e = new InvestmentDelegatedEvent(recommendation, providerId);
Events.fire(e);
if (recommendation.isConfirmationRequired()) {
// confirmation required, delegation successful => forget
discard(loan);
} else {
// confirmation not required, delegation successful => make available for direct investment later
skip(loan);
}
return false;
case INVESTED:
final int confirmedAmount = response.getConfirmedAmount().getAsInt();
final Investment i = Investment.fresh(recommendation.descriptor().item(), confirmedAmount);
markSuccessfulInvestment(i);
Events.fire(new InvestmentMadeEvent(i, loan.item(), portfolioOverview));
return true;
case // still protected by CAPTCHA
SEEN_BEFORE:
return false;
default:
throw new IllegalStateException("Not possible.");
}
}
Aggregations