Skip to content
Draft
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
228 changes: 228 additions & 0 deletions CASHAPP_INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# Cash App Integration Guide

This guide demonstrates how to use the Cash App integration features in yfinance.

## Overview

The Cash App integration module provides utilities for Cash App users to:
- Manage portfolios
- Format data for Cash App workflows
- Calculate dollar-cost averaging strategies
- Get investment recommendations
- Export portfolio data

## Quick Start

### Import the Module

```python
import yfinance as yf
from yfinance.cashapp import (
CashAppPortfolio,
format_for_cashapp,
get_cashapp_watchlist,
calculate_dollar_cost_average,
get_cashapp_recommendations
)
```

## Portfolio Management

### Creating a Portfolio

```python
# Create an empty portfolio
portfolio = CashAppPortfolio()

# Or initialize with holdings
holdings = {'AAPL': 10, 'MSFT': 5, 'GOOGL': 2}
portfolio = CashAppPortfolio(holdings)
```

### Adding Positions

```python
portfolio = CashAppPortfolio()
portfolio.add_position('AAPL', 10)
portfolio.add_position('MSFT', 5)
portfolio.add_position('TSLA', 3)
```

### Getting Portfolio Value

```python
# Get detailed portfolio information
portfolio_data = portfolio.get_portfolio_value()
print(f"Total Value: ${portfolio_data['total_value']:.2f}")

# View individual positions
for ticker, info in portfolio_data['positions'].items():
print(f"{ticker}: {info['shares']} shares @ ${info['price']:.2f} = ${info['value']:.2f}")
```

### Portfolio Summary DataFrame

```python
# Get a pandas DataFrame summary
df = portfolio.get_portfolio_summary()
print(df)
```

### Export Portfolio

```python
# Export to CSV
portfolio.export_to_csv('my_portfolio.csv')

# Export to JSON
portfolio.export_to_json('my_portfolio.json')
```

### Performance Analysis

```python
# Get performance metrics for different periods
performance_1d = portfolio.get_performance('1d')
performance_1mo = portfolio.get_performance('1mo')
performance_1y = portfolio.get_performance('1y')

for ticker, perf in performance_1mo.items():
if 'error' not in perf:
print(f"{ticker}: {perf['change_pct']:.2f}% change")
```

## Data Formatting

### Format Quote Data

```python
# Get Cash App-friendly quote format
quote = format_for_cashapp('AAPL', 'quote')
print(f"{quote['name']}: ${quote['price']:.2f} ({quote['change_percent']:.2f}%)")
```

### Format Historical Data

```python
# Get historical price data
history = format_for_cashapp('AAPL', 'history')
print(f"Price history: {len(history['prices'])} data points")
```

### Format Company Info

```python
# Get company information
info = format_for_cashapp('AAPL', 'info')
print(f"Sector: {info['sector']}")
print(f"Industry: {info['industry']}")
```

## Watchlist Management

### Create a Watchlist

```python
# Create a watchlist from multiple tickers
tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA']
watchlist = get_cashapp_watchlist(tickers)

# Display the watchlist
print(watchlist[['symbol', 'name', 'price', 'change_percent']])
```

## Dollar-Cost Averaging (DCA)

### Calculate DCA Strategy

```python
# Calculate DCA results for investing $100 monthly
dca_results = calculate_dollar_cost_average(
ticker='AAPL',
amount=100,
frequency='monthly',
start_date='2023-01-01',
end_date='2024-01-01'
)

print(f"Total Invested: ${dca_results['total_invested']:.2f}")
print(f"Total Shares: {dca_results['total_shares']:.2f}")
print(f"Average Cost Basis: ${dca_results['average_cost_basis']:.2f}")
print(f"Current Value: ${dca_results['current_value']:.2f}")
print(f"Total Return: {dca_results['total_return_pct']:.2f}%")
```

### Different Frequencies

```python
# Daily DCA
dca_daily = calculate_dollar_cost_average('AAPL', 10, 'daily')

# Weekly DCA
dca_weekly = calculate_dollar_cost_average('AAPL', 50, 'weekly')

# Monthly DCA (default)
dca_monthly = calculate_dollar_cost_average('AAPL', 200, 'monthly')
```

## Investment Recommendations

### Get Recommendations

```python
# Get investment recommendations
recommendations = get_cashapp_recommendations('AAPL')

print(f"Current Price: ${recommendations['current_price']:.2f}")
print(f"Target Price: ${recommendations['target_price']:.2f}")
print(f"Upside Potential: {recommendations['upside_potential_pct']:.2f}%")
print(f"Recommendation: {recommendations['recommendation']}")
```

## Complete Example

```python
import yfinance as yf
from yfinance.cashapp import CashAppPortfolio, format_for_cashapp, get_cashapp_watchlist

# Create and manage a portfolio
portfolio = CashAppPortfolio({
'AAPL': 10,
'MSFT': 5,
'GOOGL': 2
})

# Add more positions
portfolio.add_position('TSLA', 3)

# Get portfolio summary
summary = portfolio.get_portfolio_summary()
print("Portfolio Summary:")
print(summary)

# Get portfolio value
value = portfolio.get_portfolio_value()
print(f"\nTotal Portfolio Value: ${value['total_value']:.2f}")

# Export portfolio
portfolio.export_to_csv('cashapp_portfolio.csv')

# Create a watchlist
watchlist = get_cashapp_watchlist(['AAPL', 'MSFT', 'GOOGL', 'AMZN'])
print("\nWatchlist:")
print(watchlist[['symbol', 'price', 'change_percent']])
```

## Notes

- Cash App integration uses yfinance data sources (Yahoo Finance)
- All prices and data are fetched in real-time
- Portfolio calculations are based on current market prices
- Export formats are compatible with common spreadsheet applications
- Dollar-cost averaging calculations use historical price data

## Limitations

- Cash App doesn't provide a public API for trading, so this integration focuses on data analysis and portfolio management
- All data is sourced from Yahoo Finance via yfinance
- Portfolio tracking is local and not synced with Cash App accounts
168 changes: 168 additions & 0 deletions tests/test_cashapp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
"""
Tests for Cash App Integration

To run all tests in suite from commandline:
python -m unittest tests.test_cashapp

Specific test class:
python -m unittest tests.test_cashapp.TestCashAppPortfolio
"""

import unittest
import pandas as pd
from datetime import datetime

Check failure on line 13 in tests/test_cashapp.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

tests/test_cashapp.py:13:22: F401 `datetime.datetime` imported but unused

from tests.context import yfinance as yf

Check failure on line 15 in tests/test_cashapp.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

tests/test_cashapp.py:15:39: F401 `tests.context.yfinance` imported but unused
from yfinance.cashapp import (
CashAppPortfolio,
format_for_cashapp,
get_cashapp_watchlist,
calculate_dollar_cost_average,
get_cashapp_recommendations
)


class TestCashAppPortfolio(unittest.TestCase):
"""Test CashAppPortfolio class"""

def test_init_empty(self):
"""Test initializing empty portfolio"""
portfolio = CashAppPortfolio()
self.assertEqual(portfolio.holdings, {})
self.assertIsNone(portfolio._tickers)

def test_init_with_holdings(self):
"""Test initializing portfolio with holdings"""
holdings = {'AAPL': 10, 'MSFT': 5}
portfolio = CashAppPortfolio(holdings)
self.assertEqual(portfolio.holdings, holdings)

def test_add_position(self):
"""Test adding a position"""
portfolio = CashAppPortfolio()
portfolio.add_position('AAPL', 10)
self.assertEqual(portfolio.holdings['AAPL'], 10)

def test_add_position_update(self):
"""Test updating existing position"""
portfolio = CashAppPortfolio({'AAPL': 10})
portfolio.add_position('AAPL', 5)
self.assertEqual(portfolio.holdings['AAPL'], 15)

def test_remove_position(self):
"""Test removing a position"""
portfolio = CashAppPortfolio({'AAPL': 10, 'MSFT': 5})
portfolio.remove_position('AAPL')
self.assertNotIn('AAPL', portfolio.holdings)
self.assertIn('MSFT', portfolio.holdings)

def test_get_portfolio_value_structure(self):
"""Test portfolio value structure"""
portfolio = CashAppPortfolio({'AAPL': 10})
result = portfolio.get_portfolio_value()

self.assertIn('total_value', result)
self.assertIn('positions', result)
self.assertIn('last_updated', result)
self.assertIsInstance(result['positions'], dict)

def test_get_portfolio_summary(self):
"""Test portfolio summary DataFrame"""
portfolio = CashAppPortfolio({'AAPL': 10})
df = portfolio.get_portfolio_summary()

self.assertIsInstance(df, pd.DataFrame)
if not df.empty:
self.assertIn('Ticker', df.columns)
self.assertIn('Shares', df.columns)
self.assertIn('Price', df.columns)
self.assertIn('Value', df.columns)
self.assertIn('Weight %', df.columns)


class TestFormatForCashApp(unittest.TestCase):
"""Test format_for_cashapp function"""

def test_format_quote(self):
"""Test formatting quote data"""
result = format_for_cashapp('AAPL', 'quote')

self.assertIsInstance(result, dict)
self.assertEqual(result['symbol'], 'AAPL')
self.assertIn('name', result)
self.assertIn('price', result)
self.assertIn('change', result)
self.assertIn('change_percent', result)

def test_format_history(self):
"""Test formatting history data"""
result = format_for_cashapp('AAPL', 'history')

self.assertIsInstance(result, dict)
if result: # May be empty if no data
self.assertEqual(result['symbol'], 'AAPL')
self.assertIn('dates', result)
self.assertIn('prices', result)

def test_format_info(self):
"""Test formatting info data"""
result = format_for_cashapp('AAPL', 'info')

self.assertIsInstance(result, dict)
self.assertEqual(result['symbol'], 'AAPL')
self.assertIn('name', result)

def test_format_invalid_type(self):
"""Test invalid data type"""
with self.assertRaises(ValueError):
format_for_cashapp('AAPL', 'invalid')


class TestCashAppWatchlist(unittest.TestCase):
"""Test get_cashapp_watchlist function"""

def test_watchlist_basic(self):
"""Test creating a watchlist"""
tickers = ['AAPL', 'MSFT']
df = get_cashapp_watchlist(tickers)

self.assertIsInstance(df, pd.DataFrame)
self.assertEqual(len(df), len(tickers))
if not df.empty:
self.assertIn('symbol', df.columns)
self.assertIn('price', df.columns)


class TestDollarCostAverage(unittest.TestCase):
"""Test calculate_dollar_cost_average function"""

def test_dca_structure(self):
"""Test DCA result structure"""
result = calculate_dollar_cost_average('AAPL', 100, 'monthly')

self.assertIsInstance(result, dict)
if 'error' not in result:
self.assertIn('ticker', result)
self.assertIn('strategy', result)
self.assertIn('frequency', result)
self.assertIn('total_invested', result)
self.assertIn('total_shares', result)
self.assertIn('transactions', result)


class TestCashAppRecommendations(unittest.TestCase):
"""Test get_cashapp_recommendations function"""

def test_recommendations_structure(self):
"""Test recommendations result structure"""
result = get_cashapp_recommendations('AAPL')

self.assertIsInstance(result, dict)
self.assertIn('ticker', result)
if 'error' not in result:
self.assertIn('current_price', result)
self.assertIn('recommendation_summary', result)


if __name__ == '__main__':
unittest.main()
Loading
Loading