-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add entry price support for trailing stop-loss calculations #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add parse_ticker_with_price() utility function that parses tickers in format 'TICKER' or 'TICKER:PRICE' (e.g., "AAPL:150", "SHOP.TO:200"). Add Config.tickers_with_prices property that returns list of (ticker, entry_price) tuples, supporting mixed format usage. Includes comprehensive test coverage for: - Plain ticker parsing - Ticker with price parsing - Canadian tickers (e.g., SHOP.TO:200) - Error cases (invalid price, negative price, empty strings) - Config property integration - Backward compatibility Entry prices are runtime parameters only (not stored in database). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add entry_price field to StockPrice dataclass to store user-provided
entry prices alongside fetched market data.
Update PriceFetcher.fetch_price() to accept optional entry_price
parameter and pass it through to StockPrice construction.
Update PriceFetcher.fetch_multiple() to handle both string format
("AAPL") and tuple format (("AAPL", 150.0)) for mixed usage.
Add comprehensive tests for:
- Fetching with entry price
- Fetching without entry price (backward compatibility)
- Mixed format (some tickers with prices, some without)
- Entry price with cache updates
- Entry price persistence through data flow
All existing tests continue to pass, ensuring backward compatibility.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add entry_price field to StopLossResult dataclass to store and display user-provided entry prices in calculation results. Update all calculator methods to pass entry_price from StockPrice to StopLossResult: - calculate_simple() - passes entry_price through - calculate_trailing() - passes entry_price through - calculate_atr_stop_loss() - passes entry_price through Add comprehensive tests verifying: - Entry price flows through all calculation methods - Entry price is display-only (doesn't affect calculations) - Entry price works with all modes (simple, trailing, ATR) - Entry price is independent of base_price parameter - Backward compatibility (None when not provided) Entry price is for display purposes only and does not affect stop-loss calculations. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Update CLI argument parsing to parse TICKER:PRICE format from both command line arguments and config file. Integrate entry price into calculation logic: - Simple/ATR modes: entry price becomes base_price (overrides 52-week high) - Trailing mode: entry price sets floor for high water mark via max(db_hwm, entry_price) - Mixed usage: tickers without entry prices use current price/database HWM Key changes: - Parse CLI args with parse_ticker_with_price() - Use config.tickers_with_prices for config-based tickers - Pass list of (ticker, entry_price) tuples to PriceFetcher.fetch_multiple() - Extract ticker from tuples for historical data fetching - Apply entry price logic in calculation section for all three modes Entry price provides better stop-loss positioning when you know your actual entry point, ensuring stops are calculated from your true cost basis. All existing tests pass, maintaining full backward compatibility. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add dynamic Entry Price column to results table that appears only when at least one ticker has an entry price specified. Column displays in magenta color to distinguish from other price columns: - Current Price (white) - Entry Price (magenta) - NEW - 52-Week High (cyan) - Stop-Loss Price (green/red based on position) Layout automatically adjusts based on data available: - Entry Price column appears after Current Price - Only shown when entry prices are present - Shows "N/A" for tickers without entry prices in mixed usage This provides clear visibility into which price basis was used for calculations, helping users verify their stop-loss positioning. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive documentation for entry price support in README.md: - New "Entry Price Support" section after "Custom Percentage" - CLI usage examples with TICKER:PRICE format - How it works for each mode (simple, trailing, ATR) - Example output showing Entry Price column - Config file format examples Update config.toml with entry price format: - Add format comment explaining TICKER:PRICE syntax - Show commented examples with entry prices - Demonstrate mixed usage (some with prices, some without) Entry price support allows users to calculate stop-losses based on their actual entry point rather than current market price, providing more accurate risk management based on true cost basis. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add validation to reject entry prices when using simple or ATR modes, as the financial math produces misleading risk calculations in these modes. Problem identified: - Simple/ATR with entry price: stop = entry * (1 - %) - Risk calculation: current - stop - When stock is UP from entry: Shows huge "risk" (nonsensical) - When stock is DOWN: Shows negative risk or stop > current Only trailing mode makes financial sense: - Entry price sets minimum high water mark: max(db_hwm, entry_price) - Stop trails from highest point since entry - Risk correctly shows distance from current to trailing stop Changes: - Add validation after mode determination in CLI - Clear error message directing users to use --trailing - Remove entry price logic from simple/ATR calculation paths - Update documentation to clarify "trailing mode only" - Update config.toml comments All 83 tests pass. Backward compatibility maintained. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Code ReviewFound 2 issues that need attention: Issue 1: Cache Mutation Side EffectFile: When using the cache with an trailing-stops/src/trailing_stop_loss/fetcher.py Lines 46 to 52 in 28ccf39
The Problem: Example failure scenario:
Suggested fix: if use_cache and ticker in self._cache:
cached = self._cache[ticker]
# Return a copy with updated entry price if provided
if entry_price is not None:
return dataclasses.replace(cached, entry_price=entry_price)
return cachedIssue 2: Type Annotation MismatchFile: The type annotation doesn't match the actual implementation: trailing-stops/src/trailing_stop_loss/fetcher.py Lines 84 to 87 in 28ccf39
The Problem: The test file even uses the correct type: trailing-stops/tests/test_fetcher.py Lines 153 to 154 in 28ccf39
Impact: Suggested fix: def fetch_multiple(
self, tickers: list[str | tuple[str, float | None]], skip_errors: bool = True
) -> dict[str, StockPrice | Exception]:Reviewed for bugs and CLAUDE.md compliance |
- Use dataclasses.replace() to avoid mutating cached StockPrice objects - Fix type annotation to allow mixed lists in fetch_multiple() Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Summary
Add support for specifying entry prices directly with ticker symbols using
TICKER:PRICEformat (e.g.,AAPL:150,SHOP.TO:200). Entry prices work exclusively with trailing mode to set a floor for high water mark calculations based on actual cost basis.Usage
CLI:
Config:
How It Works
Entry price sets the minimum high water mark in trailing mode:
hwm = max(database_hwm, entry_price)Example:
Why Trailing Mode Only?
Entry prices are restricted to trailing mode because:
Implementation Details
Built in 7 incremental commits with full test coverage:
parse_ticker_with_price()utility functionStockPriceandPriceFetcherStopLossResultwithentry_pricefieldTesting
Test Plan
Breaking Changes
None - fully backward compatible.
🤖 Generated with Claude Code