Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
320 changes: 173 additions & 147 deletions src/main/java/com/open/spring/mvc/bank/Bank.java

Large diffs are not rendered by default.

822 changes: 226 additions & 596 deletions src/main/java/com/open/spring/mvc/bank/BankApiController.java

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions src/main/java/com/open/spring/mvc/bank/BankJpaRepository.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
// src/main/java/com/open/spring/mvc/bank/BankJpaRepository.java
package com.open.spring.mvc.bank;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

public interface BankJpaRepository extends JpaRepository<Bank, Long> {
// Find bank by person_id
Bank findByPersonId(Long personId);
Bank findByUid(String uid);
List<Bank> findByUidContainingIgnoreCase(String uid);
// Find top 10 banks ordered by balance in descending order (for leaderboard)
Bank findByUid(String uid);
List<Bank> findByUidContainingIgnoreCase(String uid);

List<Bank> findTop10ByOrderByBalanceDesc();

@Query("SELECT p FROM Bank p ORDER BY CAST(p.balance AS double) DESC LIMIT 5")
List<Bank> findTop5ByOrderByBalanceDesc();

// Alternative deletion methods for troubleshooting

@Modifying
@Transactional
@Query("DELETE FROM Bank b")
void deleteAllBanks();

@Modifying
@Transactional
@Query(value = "TRUNCATE TABLE bank RESTART IDENTITY CASCADE", nativeQuery = true)
void truncateBankTable();

// For debugging - check if there are any orphaned records

@Query("SELECT COUNT(b) FROM Bank b WHERE b.person IS NULL")
long countOrphanedBanks();
}
}
74 changes: 25 additions & 49 deletions src/main/java/com/open/spring/mvc/bank/BankService.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// src/main/java/com/open/spring/mvc/bank/BankService.java
package com.open.spring.mvc.bank;

import org.slf4j.Logger;
Expand All @@ -14,7 +15,6 @@ public class BankService {
@Autowired
private BankJpaRepository bankRepository;

// Find by Person ID
public Bank findByPersonId(Long personId) {
Bank bank = bankRepository.findByPersonId(personId);
if (bank == null) {
Expand All @@ -28,59 +28,51 @@ public Bank findByPersonId(Long personId) {
public void clearAllBanks() {
try {
logger.info("Starting to clear all bank records...");

// Get count before deletion for verification

long initialCount = bankRepository.count();
logger.info("Initial bank record count: {}", initialCount);

if (initialCount == 0) {
logger.info("No bank records to delete");
return;
}

// Method 1: Try simple deleteAll first

bankRepository.deleteAll();
bankRepository.flush(); // Force immediate execution

// Verify deletion
bankRepository.flush();

long finalCount = bankRepository.count();
logger.info("Final bank record count after deletion: {}", finalCount);

if (finalCount > 0) {
logger.warn("Some records were not deleted. Attempting alternative deletion method...");

// Method 2: Delete by batches if simple deleteAll fails
clearAllBanksByBatch();
} else {
logger.info("Successfully cleared all {} bank records", initialCount);
}

} catch (Exception e) {
logger.error("Error clearing bank records: ", e);
throw new RuntimeException("Failed to clear bank records: " + e.getMessage(), e);
}
}

@Transactional
public void clearAllBanksByBatch() {
try {
logger.info("Attempting batch deletion of bank records...");

// Get all bank IDs

var allBanks = bankRepository.findAll();
logger.info("Found {} bank records to delete", allBanks.size());

// Delete in batches of 50 to avoid memory issues

int batchSize = 50;
for (int i = 0; i < allBanks.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, allBanks.size());
var batch = allBanks.subList(i, endIndex);

logger.info("Deleting batch {}-{} of {}", i + 1, endIndex, allBanks.size());

for (Bank bank : batch) {
try {
// First, break the relationship with Person if it exists
if (bank.getPerson() != null) {
bank.getPerson().setBanks(null);
bank.setPerson(null);
Expand All @@ -90,77 +82,66 @@ public void clearAllBanksByBatch() {
logger.error("Failed to delete bank with ID: {}", bank.getId(), e);
}
}

// Flush after each batch

bankRepository.flush();
}

// Final verification

long remainingCount = bankRepository.count();
logger.info("Remaining bank records after batch deletion: {}", remainingCount);

} catch (Exception e) {
logger.error("Error in batch deletion: ", e);
throw new RuntimeException("Failed to clear bank records via batch deletion: " + e.getMessage(), e);
}
}

@Transactional
public void clearAllBanksForce() {
try {
logger.info("Attempting force deletion using native SQL...");

// This would require adding a native query method to the repository
// For now, we'll use the existing methods with proper error handling

var allBanks = bankRepository.findAll();

for (Bank bank : allBanks) {
try {
// Manually handle the relationship
if (bank.getPerson() != null) {
bank.getPerson().setBanks(null);
}
bank.setPerson(null);
bankRepository.save(bank); // Save the changes first
bankRepository.save(bank);
} catch (Exception e) {
logger.warn("Could not update relationships for bank ID: {}", bank.getId());
}
}

// Now try to delete all

bankRepository.deleteAll();
bankRepository.flush();

logger.info("Force deletion completed");

} catch (Exception e) {
logger.error("Error in force deletion: ", e);
throw new RuntimeException("Failed to force clear bank records: " + e.getMessage(), e);
}
}

// Request a loan using the Person ID
@Transactional
public Bank requestLoan(Long personId, double loanAmount) {
// Validate input
if (personId == null) {
logger.error("Invalid Person ID provided for loan request");
throw new IllegalArgumentException("Person ID cannot be null");
}

if (loanAmount <= 0) {
logger.error("Invalid loan amount: {}", loanAmount);
throw new IllegalArgumentException("Loan amount must be positive");
}

// Find bank account
Bank bank = bankRepository.findByPersonId(personId);
if (bank == null) {
logger.error("No bank account found for Person ID: {}", personId);
throw new RuntimeException("Bank account not found for Person ID: " + personId);
}

// Process loan request
try {
bank.requestLoan(loanAmount);
logger.info("Loan request processed for Person ID: {} amount: {}", personId, loanAmount);
Expand All @@ -170,29 +151,24 @@ public Bank requestLoan(Long personId, double loanAmount) {
throw new RuntimeException("Failed to process loan request", e);
}
}

// Repay a loan using the Person ID

@Transactional
public Bank repayLoan(Long personId, double repaymentAmount) {
// Validate input
if (personId == null) {
logger.error("Invalid Person ID provided for loan repayment");
throw new IllegalArgumentException("Person ID cannot be null");
}

if (repaymentAmount <= 0) {
logger.error("Invalid repayment amount: {}", repaymentAmount);
throw new IllegalArgumentException("Repayment amount must be positive");
}

// Find bank account
Bank bank = bankRepository.findByPersonId(personId);
if (bank == null) {
logger.error("No bank account found for Person ID: {}", personId);
throw new RuntimeException("Bank account not found for Person ID: " + personId);
}

// Process loan repayment
try {
bank.repayLoan(repaymentAmount);
logger.info("Loan repayment processed for Person ID: {} amount: {}", personId, repaymentAmount);
Expand All @@ -202,4 +178,4 @@ public Bank repayLoan(Long personId, double repaymentAmount) {
throw new RuntimeException("Failed to process loan repayment: " + e.getMessage(), e);
}
}
}
}
38 changes: 38 additions & 0 deletions src/main/java/com/open/spring/mvc/quant/BacktestResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.open.spring.mvc.quant;

import java.util.ArrayList;
import java.util.List;

import lombok.Data;

@Data
public class BacktestResult {

// Chart series
private List<String> dates = new ArrayList<>();
private List<Double> portfolioValue = new ArrayList<>();
private List<Double> benchmarkValue = new ArrayList<>(); // buy & hold

// Returns series (daily %)
private List<Double> returns = new ArrayList<>();

// Trades list
private List<Trade> trades = new ArrayList<>();

// Quick metrics
private double totalReturnPct;
private double maxDrawdownPct;
private double winRatePct;

private String note;

@Data
public static class Trade {
private String date;
private String side; // BUY / SELL
private int qty;
private double price;
private double cashAfter;
private double positionAfter;
}
}
Loading