quantflow-finance 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: quantflow-finance
3
+ Version: 0.1.0
4
+ Summary: Essential quantitative finance tools for modern portfolio management
5
+ Home-page: https://github.com/jeevanba273/quantflow
6
+ Author: JEEVAN B A
7
+ Author-email: jeevanba273@gmail.com
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Financial and Insurance Industry
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: numpy>=1.20.0
17
+ Requires-Dist: scipy>=1.7.0
18
+ Requires-Dist: pandas>=1.3.0
19
+ Requires-Dist: matplotlib>=3.3.0
20
+ Requires-Dist: yfinance>=0.1.70
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=6.0; extra == "dev"
23
+ Requires-Dist: black; extra == "dev"
24
+ Requires-Dist: flake8; extra == "dev"
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: provides-extra
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ A comprehensive Python package for options pricing, risk analytics, and market data processing.
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,41 @@
1
+ """
2
+ Setup configuration for QuantFlow package.
3
+ """
4
+
5
+ from setuptools import setup, find_packages
6
+
7
+ setup(
8
+ name="quantflow-finance",
9
+ version="0.1.0",
10
+ author="JEEVAN B A",
11
+ author_email="jeevanba273@gmail.com",
12
+ description="Essential quantitative finance tools for modern portfolio management",
13
+ long_description="A comprehensive Python package for options pricing, risk analytics, and market data processing.",
14
+ long_description_content_type="text/markdown",
15
+ url="https://github.com/jeevanba273/quantflow",
16
+ package_dir={"": "src"},
17
+ packages=find_packages(where="src"),
18
+ classifiers=[
19
+ "Development Status :: 3 - Alpha",
20
+ "Intended Audience :: Financial and Insurance Industry",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ ],
26
+ python_requires=">=3.8",
27
+ install_requires=[
28
+ "numpy>=1.20.0",
29
+ "scipy>=1.7.0",
30
+ "pandas>=1.3.0",
31
+ "matplotlib>=3.3.0",
32
+ "yfinance>=0.1.70",
33
+ ],
34
+ extras_require={
35
+ "dev": [
36
+ "pytest>=6.0",
37
+ "black",
38
+ "flake8",
39
+ ],
40
+ },
41
+ )
@@ -0,0 +1,16 @@
1
+ """
2
+ QuantFlow: Essential quantitative finance tools for modern portfolio management.
3
+
4
+ A comprehensive Python package for options pricing, risk analytics, and market data processing.
5
+ """
6
+
7
+ __version__ = "0.1.0"
8
+ __author__ = "JEEVAN B A"
9
+ __email__ = "jeevanba273@gmail.com"
10
+
11
+ # Import main classes for easy access
12
+ from .options.black_scholes import BlackScholes
13
+ from .risk.metrics import RiskMetrics
14
+ from .data.fetcher import MarketData
15
+
16
+ __all__ = ['BlackScholes', 'RiskMetrics', 'MarketData']
@@ -0,0 +1,10 @@
1
+ """
2
+ Options pricing and Greeks calculation module.
3
+
4
+ This module provides implementations of various option pricing models including
5
+ the Black-Scholes-Merton model for European options.
6
+ """
7
+
8
+ from .black_scholes import BlackScholes
9
+
10
+ __all__ = ['BlackScholes']
@@ -0,0 +1,89 @@
1
+ """
2
+ Black-Scholes option pricing model implementation.
3
+ """
4
+
5
+ import numpy as np
6
+ from scipy.stats import norm
7
+
8
+
9
+ class BlackScholes:
10
+ """
11
+ Black-Scholes option pricing model.
12
+
13
+ Parameters:
14
+ S: Current stock price
15
+ K: Strike price
16
+ T: Time to expiration in years
17
+ r: Risk-free interest rate
18
+ sigma: Volatility
19
+ option_type: 'call' or 'put'
20
+ """
21
+
22
+ def __init__(self, S, K, T, r, sigma, option_type='call'):
23
+ self.S = float(S)
24
+ self.K = float(K)
25
+ self.T = float(T)
26
+ self.r = float(r)
27
+ self.sigma = float(sigma)
28
+ self.option_type = option_type.lower()
29
+
30
+ def price(self):
31
+ """Calculate option price using Black-Scholes formula."""
32
+ # Calculate d1 and d2 parameters
33
+ d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma**2) * self.T) / (self.sigma * np.sqrt(self.T))
34
+ d2 = d1 - self.sigma * np.sqrt(self.T)
35
+
36
+ if self.option_type == 'call':
37
+ # Call option formula: S*N(d1) - K*e^(-rT)*N(d2)
38
+ return self.S * norm.cdf(d1) - self.K * np.exp(-self.r * self.T) * norm.cdf(d2)
39
+ else:
40
+ # Put option formula: K*e^(-rT)*N(-d2) - S*N(-d1)
41
+ return self.K * np.exp(-self.r * self.T) * norm.cdf(-d2) - self.S * norm.cdf(-d1)
42
+
43
+ def delta(self):
44
+ """Calculate option delta (price sensitivity to stock price)."""
45
+ d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma**2) * self.T) / (self.sigma * np.sqrt(self.T))
46
+
47
+ if self.option_type == 'call':
48
+ return norm.cdf(d1)
49
+ else:
50
+ return norm.cdf(d1) - 1
51
+
52
+ def gamma(self):
53
+ """Calculate option gamma (rate of change of delta)."""
54
+ d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma**2) * self.T) / (self.sigma * np.sqrt(self.T))
55
+
56
+ # Gamma is the same for both calls and puts
57
+ return norm.pdf(d1) / (self.S * self.sigma * np.sqrt(self.T))
58
+
59
+ def theta(self):
60
+ """Calculate option theta (time decay per year)."""
61
+ d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma**2) * self.T) / (self.sigma * np.sqrt(self.T))
62
+ d2 = d1 - self.sigma * np.sqrt(self.T)
63
+
64
+ first_term = -(self.S * norm.pdf(d1) * self.sigma) / (2 * np.sqrt(self.T))
65
+
66
+ if self.option_type == 'call':
67
+ second_term = -self.r * self.K * np.exp(-self.r * self.T) * norm.cdf(d2)
68
+ else:
69
+ second_term = self.r * self.K * np.exp(-self.r * self.T) * norm.cdf(-d2)
70
+
71
+ return first_term + second_term
72
+
73
+ def vega(self):
74
+ """Calculate option vega (sensitivity to volatility change)."""
75
+ d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma**2) * self.T) / (self.sigma * np.sqrt(self.T))
76
+
77
+ # Vega is the same for both calls and puts
78
+ # Divide by 100 to get sensitivity per 1% volatility change
79
+ return (self.S * norm.pdf(d1) * np.sqrt(self.T)) / 100
80
+
81
+ def greeks(self):
82
+ """Calculate all Greeks at once."""
83
+ return {
84
+ 'price': self.price(),
85
+ 'delta': self.delta(),
86
+ 'gamma': self.gamma(),
87
+ 'theta': self.theta(),
88
+ 'vega': self.vega()
89
+ }
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: quantflow-finance
3
+ Version: 0.1.0
4
+ Summary: Essential quantitative finance tools for modern portfolio management
5
+ Home-page: https://github.com/jeevanba273/quantflow
6
+ Author: JEEVAN B A
7
+ Author-email: jeevanba273@gmail.com
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Financial and Insurance Industry
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: numpy>=1.20.0
17
+ Requires-Dist: scipy>=1.7.0
18
+ Requires-Dist: pandas>=1.3.0
19
+ Requires-Dist: matplotlib>=3.3.0
20
+ Requires-Dist: yfinance>=0.1.70
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=6.0; extra == "dev"
23
+ Requires-Dist: black; extra == "dev"
24
+ Requires-Dist: flake8; extra == "dev"
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: provides-extra
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ A comprehensive Python package for options pricing, risk analytics, and market data processing.
@@ -0,0 +1,12 @@
1
+ setup.py
2
+ src/quantflow/__init__.py
3
+ src/quantflow/options/__init__.py
4
+ src/quantflow/options/black_scholes.py
5
+ src/quantflow_finance.egg-info/PKG-INFO
6
+ src/quantflow_finance.egg-info/SOURCES.txt
7
+ src/quantflow_finance.egg-info/dependency_links.txt
8
+ src/quantflow_finance.egg-info/requires.txt
9
+ src/quantflow_finance.egg-info/top_level.txt
10
+ tests/test_black_scholes.py
11
+ tests/test_market_data.py
12
+ tests/test_risk_metrics.py
@@ -0,0 +1,10 @@
1
+ numpy>=1.20.0
2
+ scipy>=1.7.0
3
+ pandas>=1.3.0
4
+ matplotlib>=3.3.0
5
+ yfinance>=0.1.70
6
+
7
+ [dev]
8
+ pytest>=6.0
9
+ black
10
+ flake8
@@ -0,0 +1,106 @@
1
+ """
2
+ Test the Black-Scholes implementation.
3
+ """
4
+
5
+ import sys
6
+ import os
7
+
8
+ # Add the src folder to Python path so we can import our code
9
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src'))
10
+
11
+ from quantflow.options.black_scholes import BlackScholes
12
+
13
+
14
+ def test_basic_call_option():
15
+ """Test a basic call option price."""
16
+ # Create a call option: Stock=$100, Strike=$100, 1 year, 5% rate, 20% volatility
17
+ option = BlackScholes(S=100, K=100, T=1, r=0.05, sigma=0.2, option_type='call')
18
+ price = option.price()
19
+
20
+ print(f"Call option price: ${price:.2f}")
21
+
22
+ # The theoretical price should be around $10.45
23
+ assert 10.0 < price < 11.0, f"Price {price} seems wrong for this call option"
24
+ print("āœ“ Call option test passed!")
25
+
26
+ def test_delta_calculation():
27
+ """Test delta calculation."""
28
+ # Same option as before
29
+ option = BlackScholes(S=100, K=100, T=1, r=0.05, sigma=0.2, option_type='call')
30
+ delta = option.delta()
31
+
32
+ print(f"Call option delta: {delta:.3f}")
33
+
34
+ # Delta for ATM call should be around 0.6
35
+ assert 0.55 < delta < 0.65, f"Delta {delta} seems wrong"
36
+ print("āœ“ Delta test passed!")
37
+
38
+ def test_gamma_calculation():
39
+ """Test gamma calculation."""
40
+ # Same option as before
41
+ option = BlackScholes(S=100, K=100, T=1, r=0.05, sigma=0.2, option_type='call')
42
+ gamma = option.gamma()
43
+
44
+ print(f"Call option gamma: {gamma:.4f}")
45
+
46
+ # Gamma for ATM options should be around 0.02
47
+ assert 0.015 < gamma < 0.025, f"Gamma {gamma} seems wrong"
48
+ print("āœ“ Gamma test passed!")
49
+
50
+ def test_theta_calculation():
51
+ """Test theta calculation."""
52
+ # Same option as before
53
+ option = BlackScholes(S=100, K=100, T=1, r=0.05, sigma=0.2, option_type='call')
54
+ theta = option.theta()
55
+
56
+ print(f"Call option theta: ${theta:.2f} per year")
57
+ print(f"Daily theta: ${theta/365:.3f} per day")
58
+
59
+ # Theta should be negative for long options (time decay)
60
+ assert theta < 0, f"Theta {theta} should be negative for long options"
61
+ assert -10 < theta < -1, f"Theta {theta} seems out of reasonable range"
62
+ print("āœ“ Theta test passed!")
63
+
64
+
65
+ def test_vega_calculation():
66
+ """Test vega calculation."""
67
+ # Same option as before
68
+ option = BlackScholes(S=100, K=100, T=1, r=0.05, sigma=0.2, option_type='call')
69
+ vega = option.vega()
70
+
71
+ print(f"Call option vega: ${vega:.2f} per 1% volatility change")
72
+
73
+ # Vega should be positive (higher volatility = higher option value)
74
+ assert vega > 0, f"Vega {vega} should be positive"
75
+ assert 0.2 < vega < 0.6, f"Vega {vega} seems out of reasonable range"
76
+ print("āœ“ Vega test passed!")
77
+
78
+ def test_greeks_summary():
79
+ """Test the convenient Greeks summary function."""
80
+ option = BlackScholes(S=100, K=100, T=1, r=0.05, sigma=0.2, option_type='call')
81
+ greeks = option.greeks()
82
+
83
+ print("\nšŸ“Š Complete Greeks Summary:")
84
+ print(f"Price: ${greeks['price']:.2f}")
85
+ print(f"Delta: {greeks['delta']:.3f}")
86
+ print(f"Gamma: {greeks['gamma']:.4f}")
87
+ print(f"Theta: ${greeks['theta']:.2f}")
88
+ print(f"Vega: ${greeks['vega']:.2f}")
89
+
90
+ # Check that all values are present
91
+ assert 'price' in greeks
92
+ assert 'delta' in greeks
93
+ assert 'gamma' in greeks
94
+ assert 'theta' in greeks
95
+ assert 'vega' in greeks
96
+ print("āœ“ Greeks summary test passed!")
97
+
98
+
99
+ if __name__ == "__main__":
100
+ test_basic_call_option()
101
+ test_delta_calculation()
102
+ test_gamma_calculation()
103
+ test_theta_calculation()
104
+ test_vega_calculation()
105
+ test_greeks_summary()
106
+ print("All tests passed! šŸŽ‰")
@@ -0,0 +1,52 @@
1
+ """
2
+ Test the market data implementation.
3
+ """
4
+
5
+ import sys
6
+ import os
7
+
8
+ # Add the src folder to Python path
9
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src'))
10
+
11
+ from quantflow.data.fetcher import MarketData
12
+
13
+
14
+ def test_single_stock_fetch():
15
+ """Test fetching data for a single stock."""
16
+ print("šŸ“ˆ Fetching AAPL data...")
17
+
18
+ # Fetch Apple stock data for 6 months
19
+ data = MarketData.fetch_stock_data('AAPL', period='6mo')
20
+
21
+ print(f"Data shape: {data.shape}")
22
+ print(f"Date range: {data.index[0].date()} to {data.index[-1].date()}")
23
+ print(f"Latest price: ${data.iloc[-1, 0]:.2f}")
24
+
25
+ # Check that we got reasonable data
26
+ assert len(data) > 100, f"Expected more data points, got {len(data)}"
27
+ assert data.iloc[-1, 0] > 0, "Stock price should be positive"
28
+ print("āœ“ Single stock fetch test passed!")
29
+
30
+
31
+ def test_returns_calculation():
32
+ """Test returns calculation."""
33
+ print("\nšŸ“Š Testing returns calculation...")
34
+
35
+ # Fetch data and calculate returns
36
+ data = MarketData.fetch_stock_data('MSFT', period='3mo')
37
+ returns = MarketData.calculate_returns(data)
38
+
39
+ print(f"Returns data shape: {returns.shape}")
40
+ print(f"Average daily return: {returns.mean().iloc[0]:.4f} ({returns.mean().iloc[0]*100:.2f}%)")
41
+ print(f"Daily volatility: {returns.std().iloc[0]:.4f} ({returns.std().iloc[0]*100:.2f}%)")
42
+
43
+ # Check returns are reasonable
44
+ assert len(returns) == len(data) - 1, "Returns should have one less observation than prices"
45
+ assert not returns.isna().any().any(), "Returns should not contain NaN values"
46
+ print("āœ“ Returns calculation test passed!")
47
+
48
+
49
+ if __name__ == "__main__":
50
+ test_single_stock_fetch()
51
+ test_returns_calculation()
52
+ print("\nAll market data tests passed! šŸŽ‰")
@@ -0,0 +1,82 @@
1
+ """
2
+ Test the risk metrics implementation.
3
+ """
4
+
5
+ import sys
6
+ import os
7
+ import numpy as np
8
+
9
+ # Add the src folder to Python path
10
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src'))
11
+
12
+ from quantflow.risk.metrics import RiskMetrics
13
+
14
+
15
+ def test_var_calculation():
16
+ """Test Value at Risk calculation."""
17
+ # Create sample returns (daily returns for 1 year)
18
+ np.random.seed(42) # For reproducible results
19
+ returns = np.random.normal(0.001, 0.02, 252) # 1% annual return, 20% volatility
20
+
21
+ risk_metrics = RiskMetrics(returns)
22
+ var_5 = risk_metrics.var_historical(0.05) # 5% VaR
23
+
24
+ print(f"5% VaR: {var_5:.4f} ({var_5*100:.2f}%)")
25
+
26
+ # VaR should be negative (worst 5% of returns)
27
+ assert var_5 < 0, f"VaR should be negative, got {var_5}"
28
+ print("āœ“ VaR test passed!")
29
+
30
+
31
+ def test_sharpe_ratio():
32
+ """Test Sharpe ratio calculation."""
33
+ np.random.seed(42)
34
+ returns = np.random.normal(0.001, 0.02, 252)
35
+
36
+ risk_metrics = RiskMetrics(returns)
37
+ sharpe = risk_metrics.sharpe_ratio(risk_free_rate=0.02)
38
+
39
+ print(f"Sharpe ratio: {sharpe:.3f}")
40
+
41
+ # Sharpe ratio should be reasonable (between -2 and 3 for most portfolios)
42
+ assert -2 < sharpe < 3, f"Sharpe ratio {sharpe} seems unreasonable"
43
+ print("āœ“ Sharpe ratio test passed!")
44
+
45
+ def test_expected_shortfall():
46
+ """Test Expected Shortfall calculation."""
47
+ np.random.seed(42)
48
+ returns = np.random.normal(0.001, 0.02, 252)
49
+
50
+ risk_metrics = RiskMetrics(returns)
51
+ var_5 = risk_metrics.var_historical(0.05)
52
+ es_5 = risk_metrics.expected_shortfall(0.05)
53
+
54
+ print(f"5% Expected Shortfall: {es_5:.4f} ({es_5*100:.2f}%)")
55
+ print(f"VaR vs ES: VaR={var_5:.4f}, ES={es_5:.4f}")
56
+
57
+ # Expected Shortfall should be worse (more negative) than VaR
58
+ assert es_5 < var_5, f"Expected Shortfall {es_5} should be worse than VaR {var_5}"
59
+ print("āœ“ Expected Shortfall test passed!")
60
+
61
+
62
+ def test_max_drawdown():
63
+ """Test Maximum Drawdown calculation."""
64
+ np.random.seed(42)
65
+ returns = np.random.normal(0.001, 0.02, 252)
66
+
67
+ risk_metrics = RiskMetrics(returns)
68
+ max_dd = risk_metrics.max_drawdown()
69
+
70
+ print(f"Maximum Drawdown: {max_dd:.4f} ({max_dd*100:.2f}%)")
71
+
72
+ # Max drawdown should be negative (loss from peak)
73
+ assert max_dd <= 0, f"Max drawdown should be negative, got {max_dd}"
74
+ print("āœ“ Max drawdown test passed!")
75
+
76
+
77
+ if __name__ == "__main__":
78
+ test_var_calculation()
79
+ test_sharpe_ratio()
80
+ test_expected_shortfall()
81
+ test_max_drawdown()
82
+ print("All risk metrics tests passed! šŸŽ‰")