A comprehensive quantitative trading analysis framework implemented in Java, providing multiple trading strategies, performance analysis, and risk management capabilities using US equity data from Yahoo Finance.
- Overview
- Features
- Installation
- Quick Start
- Detailed Usage
- Project Structure
- Strategy Documentation
- Performance Metrics
- API Reference
- Examples
- Testing
- Troubleshooting
- Contributing
- License
This Java implementation provides a robust, enterprise-ready framework for quantitative trading strategy analysis including:
- Technical Analysis: Moving averages, momentum, RSI mean reversion
- Fundamental Analysis: Value vs growth, quality-based selection
- Enhanced Strategies: Volatility-adjusted and constrained portfolios
- Comprehensive Backtesting: Performance analysis and risk management
- Strategy Optimization: Parameter tuning and performance comparison
- 80 US Stocks: Diversified across 10 sectors (Technology, Financial, Healthcare, etc.)
- Yahoo Finance Integration: RESTful API client with error handling
- Data Preprocessing: Returns calculation, missing data handling, date alignment
- Unbalanced Panel Handling: Manages different trading schedules across stocks
- Charts Generation: PNG visualizations saved to
/charts/directory - Text Reports: Comprehensive analysis results saved to
/results/directory - Timestamped Files: Each analysis run creates unique timestamped output files
- Console Logging: Real-time progress monitoring with detailed logging
- Moving Average Crossover: Long/short signals based on short vs long moving averages
- Momentum Strategy: Positions based on past return momentum (configurable lookback)
- RSI Mean Reversion: Mean reversion strategy using RSI indicators (oversold/overbought)
- Equal Weight: Standard 1/N portfolio construction
- Volatility Targeting: Risk-adjusted position sizing
- Position Constraints: Maximum weight limits for risk management
- Return Metrics: Total return, annualized return, volatility
- Risk-Adjusted Metrics: Sharpe ratio, Sortino ratio, Calmar ratio
- Risk Measures: Maximum drawdown, VaR (95%), CVaR (95%), tail risk metrics
- Trading Statistics: Win rate, profit factor, average win/loss
- Rolling Analysis: Time-varying performance metrics
- Factor Analysis: Market, size, momentum, value, quality factors
- Beta Calculation: Portfolio beta relative to market
- Risk Decomposition: Systematic vs. idiosyncratic risk
- Java 11 or higher
- Maven 3.6 or higher
- Internet connection for data collection
# Clone or download the project
cd /path/to/Longshanks_Assignment
# Build the project
mvn clean compile
# Run tests
mvn test
# Package the application
mvn clean packageThe project uses Maven for dependency management. Key dependencies include:
- OkHttp: HTTP client for Yahoo Finance API
- Jackson: JSON processing and serialization
- Apache Commons Math: Mathematical operations and statistics
- SLF4J + Logback: Logging framework
- JUnit 5: Testing framework
# Run with default parameters (2020-01-01 to current date)
mvn exec:java -Dexec.mainClass="com.quantitative.trading.MainAnalysis"
# Run with custom date range
mvn exec:java -Dexec.mainClass="com.quantitative.trading.MainAnalysis" -Dexec.args="2023-01-01 2023-12-31"
# Run via test (recommended for demo)
mvn test "-Dtest=TestAnalysis#testCompleteAnalysis"After running the analysis, check the generated files:
๐ Charts (PNG files):
ls charts/
# cumulative_returns_comparison.png
# performance_metrics_comparison.png
# strategy_drawdowns.png
# rolling_sharpe_ratio.png๐ Text Report:
ls results/
# analysis_results_YYYYMMDD_HHMMSS.txt
cat results/analysis_results_*.txt# Run all tests
mvn test
# Run specific test class
mvn test -Dtest=TestAnalysis# Create shaded JAR with all dependencies
mvn clean package
# Run the JAR
java -jar target/trading-analysis-1.0.0.jar 2023-01-01 2023-12-31import com.quantitative.trading.MainAnalysis;
import java.time.LocalDate;
public class ExampleUsage {
public static void main(String[] args) {
MainAnalysis analysis = new MainAnalysis();
LocalDate startDate = LocalDate.of(2020, 1, 1);
LocalDate endDate = LocalDate.of(2024, 12, 31);
analysis.runCompleteAnalysis(startDate, endDate);
// Access results
Map<String, StrategyResult> results = analysis.getStrategyResults();
Map<String, Object> stats = analysis.getDataStatistics();
}
}import com.quantitative.trading.data.DataCollector;
import com.quantitative.trading.strategies.TechnicalStrategies;
import com.quantitative.trading.performance.PerformanceAnalyzer;
// 1. Data Collection
DataCollector collector = new DataCollector();
collector.collectData(LocalDate.of(2020, 1, 1), LocalDate.of(2024, 12, 31));
collector.calculateReturns();
Map<LocalDate, Map<String, BigDecimal>> pricesData = collector.getAlignedPriceData();
Map<LocalDate, Map<String, BigDecimal>> returnsData = collector.getAlignedReturnsData();
// 2. Strategy Implementation
TechnicalStrategies technical = new TechnicalStrategies(pricesData, returnsData);
StrategyResult maResult = technical.movingAverageCrossover(20, 50, 5);
// 3. Portfolio Construction
PortfolioConstruction portfolioConstructor = new PortfolioConstruction(returnsData);
Map<LocalDate, Map<String, BigDecimal>> weights = portfolioConstructor.equalWeight(maResult.getPositions());
maResult.setWeights(weights);
// 4. Performance Analysis
PerformanceAnalyzer analyzer = new PerformanceAnalyzer(returnsData);
Map<LocalDate, BigDecimal> portfolioReturns = analyzer.calculatePortfolioReturns(weights);
PerformanceMetrics metrics = analyzer.calculatePerformanceMetrics(portfolioReturns);
System.out.println("Sharpe Ratio: " + metrics.getSharpeRatio());
System.out.println("Annual Return: " + metrics.formatAsPercentage(metrics.getAnnualizedReturn()));
System.out.println("Max Drawdown: " + metrics.formatAsPercentage(metrics.getMaxDrawdown()));src/
โโโ main/java/com/quantitative/trading/
โ โโโ MainAnalysis.java # Main analysis pipeline
โ โโโ data/
โ โ โโโ DataCollector.java # Data collection and preprocessing
โ โ โโโ YahooFinanceClient.java # Yahoo Finance API client
โ โโโ model/
โ โ โโโ StockData.java # Stock price data model
โ โ โโโ PerformanceMetrics.java # Performance metrics model
โ โ โโโ StrategyResult.java # Strategy result model
โ โโโ strategies/
โ โ โโโ TechnicalStrategies.java # Technical analysis strategies
โ โ โโโ PortfolioConstruction.java # Portfolio construction utilities
โ โโโ performance/
โ โโโ PerformanceAnalyzer.java # Performance analysis and metrics
โโโ test/java/com/quantitative/trading/
โ โโโ TestAnalysis.java # Comprehensive test suite
โโโ pom.xml # Maven configuration
โโโ README_Java.md # This documentation
TechnicalStrategies technical = new TechnicalStrategies(pricesData, returnsData);
StrategyResult result = technical.movingAverageCrossover(
shortWindow, // Short moving average period (e.g., 20)
longWindow, // Long moving average period (e.g., 50)
rebalanceFreq // Rebalancing frequency in days (e.g., 5)
);- Logic: Long when short MA > long MA, short when short MA < long MA
- Parameters: Configurable windows and rebalancing frequency
- Use Case: Trend-following strategy
StrategyResult result = technical.momentumStrategy(
lookback, // Momentum calculation period (e.g., 20)
rebalanceFreq // Rebalancing frequency (e.g., 5)
);- Logic: Long positive momentum, short negative momentum
- Parameters: Lookback period for momentum calculation
- Use Case: Momentum capture strategy
StrategyResult result = technical.rsiStrategy(
rsiPeriod, // RSI calculation period (e.g., 14)
oversold, // Oversold threshold (e.g., 30)
overbought, // Overbought threshold (e.g., 70)
rebalanceFreq // Rebalancing frequency (e.g., 5)
);- Logic: Long when oversold (mean reversion up), short when overbought
- Parameters: RSI period and threshold levels
- Use Case: Mean reversion strategy
PortfolioConstruction portfolioConstructor = new PortfolioConstruction(returnsData);
Map<LocalDate, Map<String, BigDecimal>> weights =
portfolioConstructor.equalWeight(positions);Map<LocalDate, Map<String, BigDecimal>> weights =
portfolioConstructor.volatilityAdjusted(positions, targetVolatility);Map<LocalDate, Map<String, BigDecimal>> weights =
portfolioConstructor.maxWeightConstraint(weights, maxWeight);Longshanks_Assignment/
โโโ charts/ # Visualization files
โ โโโ cumulative_returns_comparison.png # Strategy performance over time
โ โโโ performance_metrics_comparison.png # Metrics comparison bar chart
โ โโโ strategy_drawdowns.png # Risk analysis visualization
โ โโโ rolling_sharpe_ratio.png # Risk-adjusted performance over time
โโโ results/ # Analysis reports
โ โโโ analysis_results_YYYYMMDD_HHMMSS.txt # Timestamped detailed report
โโโ target/ # Compiled Java classes
Each analysis_results_*.txt file contains:
- Data Collection Summary: Stock count, date range, trading days
- Performance Comparison Table: All strategies with key metrics
- Strategy Rankings: Top performers by Sharpe, Total Return, Calmar ratios
- Detailed Metrics: Comprehensive statistics for each strategy including:
- Return metrics (Annualized, Total, Volatility)
- Risk metrics (Sharpe, Sortino, Calmar ratios)
- Risk measures (Max Drawdown, VaR, CVaR)
- Trading statistics (Win Rate, Profit Factor, Skewness, Kurtosis)
- Cumulative Returns: Time-series performance comparison
- Performance Metrics: Bar chart comparison of key ratios
- Drawdowns: Risk analysis showing strategy drawdown patterns
- Rolling Sharpe: Risk-adjusted performance evolution over time
- Total Return: Cumulative return over the entire period
- Annualized Return: Annualized return rate
- Volatility: Annualized standard deviation of returns
- Sharpe Ratio: (Return - Risk-free rate) / Volatility
- Sortino Ratio: (Return - Risk-free rate) / Downside deviation
- Calmar Ratio: Annual return / Maximum drawdown
- Maximum Drawdown: Largest peak-to-trough decline
- Value at Risk (VaR): 95th percentile of daily losses
- Conditional VaR: Expected loss beyond VaR threshold
- Win Rate: Percentage of profitable trades
- Profit Factor: Gross profit / Gross loss
- Average Win/Loss: Mean returns for winning/losing periods
DataCollector collector = new DataCollector();
collector.collectData(startDate, endDate);
collector.calculateReturns();
Map<LocalDate, Map<String, BigDecimal>> pricesData = collector.getAlignedPriceData();
Map<LocalDate, Map<String, BigDecimal>> returnsData = collector.getAlignedReturnsData();TechnicalStrategies technical = new TechnicalStrategies(pricesData, returnsData);
// Available methods:
// - movingAverageCrossover(shortWindow, longWindow, rebalanceFreq)
// - momentumStrategy(lookback, rebalanceFreq)
// - rsiStrategy(rsiPeriod, oversold, overbought, rebalanceFreq)PerformanceAnalyzer analyzer = new PerformanceAnalyzer(returnsData);
// Available methods:
// - calculatePortfolioReturns(weights)
// - calculatePerformanceMetrics(returns)PerformanceMetrics metrics = new PerformanceMetrics();
// Available methods:
// - formatAsPercentage(BigDecimal value)
// - formatAsDecimal(BigDecimal value)import com.quantitative.trading.MainAnalysis;
MainAnalysis analysis = new MainAnalysis();
analysis.runCompleteAnalysis(LocalDate.of(2023, 1, 1), LocalDate.of(2023, 12, 31));
// Access results
Map<String, StrategyResult> results = analysis.getStrategyResults();
for (Map.Entry<String, StrategyResult> entry : results.entrySet()) {
String strategyName = entry.getKey();
PerformanceMetrics metrics = entry.getValue().getPerformanceMetrics();
System.out.println(strategyName + ": Sharpe=" + metrics.getSharpeRatio());
}// Collect data for specific stocks
DataCollector collector = new DataCollector();
collector.collectData(LocalDate.of(2023, 1, 1), LocalDate.of(2023, 12, 31));
collector.calculateReturns();
Map<LocalDate, Map<String, BigDecimal>> pricesData = collector.getAlignedPriceData();
Map<LocalDate, Map<String, BigDecimal>> returnsData = collector.getAlignedReturnsData();
// Implement custom strategy
TechnicalStrategies technical = new TechnicalStrategies(pricesData, returnsData);
StrategyResult result = technical.movingAverageCrossover(10, 30, 5);PerformanceAnalyzer analyzer = new PerformanceAnalyzer(returnsData);
Map<LocalDate, BigDecimal> portfolioReturns = analyzer.calculatePortfolioReturns(weights);
PerformanceMetrics metrics = analyzer.calculatePerformanceMetrics(portfolioReturns);
System.out.println("Performance Summary:");
System.out.println("Annual Return: " + metrics.formatAsPercentage(metrics.getAnnualizedReturn()));
System.out.println("Volatility: " + metrics.formatAsPercentage(metrics.getAnnualizedVolatility()));
System.out.println("Sharpe Ratio: " + metrics.formatAsDecimal(metrics.getSharpeRatio()));
System.out.println("Max Drawdown: " + metrics.formatAsPercentage(metrics.getMaxDrawdown()));
System.out.println("Win Rate: " + metrics.formatAsPercentage(metrics.getWinRate()));mvn testmvn test -Dtest=TestAnalysis#testDataCollection
mvn test -Dtest=TestAnalysis#testStrategyImplementation
mvn test -Dtest=TestAnalysis#testPerformanceAnalysisThe test suite covers:
- Data collection and validation
- Strategy implementation
- Performance analysis
- Complete analysis pipeline
- Data integrity checks
Expected test output:
[INFO] Running TestAnalysis
[INFO] Testing data collection...
[INFO] โ Data collection test passed
[INFO] Testing strategy implementation...
[INFO] โ Strategy implementation test passed
[INFO] Testing performance analysis...
[INFO] โ Performance analysis test passed
[INFO] โ Complete analysis test passed
[INFO] โ Data validation test passed
# Solution: Clean and rebuild
mvn clean compile
# Check Java version
java -version # Should be 11 or higher// Solution: Use fewer stocks or different date range
DataCollector collector = new DataCollector();
// The collector automatically handles failed data requests# Solution: Increase heap size
java -Xmx2g -jar target/trading-analysis-1.0.0.jar// Solution: Check internet connection and Yahoo Finance availability
// The client includes retry logic and error handling// Use smaller date range for faster analysis
LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2023, 6, 30);// Process data in smaller chunks
// The framework is designed to handle large datasets efficiently# Clone repository
git clone <repository-url>
cd Longshanks_Assignment
# Build project
mvn clean compile
# Run tests
mvn test- Extend
TechnicalStrategiesclass - Implement strategy logic in new methods
- Add tests in
TestAnalysis.java - Update documentation
- Follow Java coding conventions
- Add JavaDoc comments for all public methods
- Include comprehensive unit tests
- Use meaningful variable and method names
- Survivorship Bias: Only includes currently traded stocks
- Look-Ahead Bias: Assumes perfect execution at close prices
- Data Quality: Yahoo Finance data may have errors or gaps
- Transaction Costs: Not included but would impact real performance
- Market Impact: Large positions could affect prices
- Liquidity: Some stocks may have liquidity constraints
- Corporate Actions: Dividends and splits handled automatically
- Overfitting: Parameter optimization may lead to overfitting
- Market Regimes: Strategies may perform differently in various market conditions
- Model Risk: Assumptions may not hold in changing market conditions
- Fundamental Data: Integrate actual P/E, P/B ratios from financial statements
- Alternative Data: Include sentiment, news, or satellite data
- International Markets: Expand to global equity markets
- Machine Learning: Implement ML-based signal generation
- Multi-Asset: Include bonds, commodities, currencies
- Dynamic Allocation: Time-varying strategy weights
- Transaction Costs: Include realistic trading costs
- Liquidity Constraints: Model liquidity limitations
- Stress Testing: Scenario-based risk analysis
This project is for educational and research purposes. Please ensure compliance with Yahoo Finance terms of service when using their data.
- Check this README for common solutions
- Review the test suite (
TestAnalysis.java) - Check the JavaDoc documentation
- Examine the example code
When reporting issues, please include:
- Java version
- Operating system
- Error messages
- Steps to reproduce
# Build and test
mvn clean test
# Run complete analysis
mvn exec:java -Dexec.mainClass="com.quantitative.trading.MainAnalysis"
# Create executable JAR
mvn clean package
# Run JAR with custom dates
java -jar target/trading-analysis-1.0.0.jar 2023-01-01 2023-12-31