1. RecommendationEngine: daysToExp used before declaration
Move daysToExp/T calculation above selectBestContract() call so the
variable exists when it is passed as daysToExpiry parameter.
2. YahooFinanceClient: Swift 6 actor-isolation on Decodable conformances
nonisolated methods on an actor still inherit actor isolation in Swift 6.
Fix: lift all three decode helpers (yfDecodeChart, yfDecodeOptions,
yfMakeContract) to file-scope free functions completely outside the actor.
File-scope functions are naturally nonisolated. Also renamed the private
JSON model structs to YFChartResponse / YFOptionsResponse to avoid any
name collisions now that they live at file scope.
3. LogTradeSheet: unused 'let s = strike' binding
Replace 'let s = strike' with 'strike != nil' since the bound value
was never referenced inside the if-body.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Portfolio:
- Alphabetize list on every add/edit (sort by ticker after upsert)
- Add DataStore.updatePortfolioPosition() and PortfolioViewModel.update()
- Add EditPositionSheet: tap any row to edit shares, cost basis, or delete
with a confirmation dialog; ticker is read-only in edit mode
- Swipe-to-delete still works as before
Setups tab (three bugs fixed):
1. Auto-refresh on first open — .task now triggers vm.refresh() when
DataStore has tickers but no cached recommendations, so the tab
populates immediately without requiring a manual ↻ tap
2. Loading state — replaced the never-set vm.isLoading check with
vm.isRefreshing so the spinner actually shows during fetch
3. Strike selection used a hardcoded T=30 days for all time horizons,
causing weekly/1DTE options to pick strikes too far OTM (near-zero
delta at actual expiry → zero bid → filtered out → no results).
selectBestContract() now receives real daysToExpiry, relaxes the
delta floor for very short expirations (≤3 days: 0.05 min vs 0.10),
and adds a closest-to-ATM fallback when the delta filter finds nothing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs:
1. Swift 6 strict concurrency: JSONDecoder().decode() inside actor-isolated
methods triggers "Main actor-isolated conformance cannot be used in
actor-isolated context". Fix: move all Decodable usage into nonisolated
helper methods (parseChart, parseOptions, makeContract) so the conformance
is invoked outside the actor's isolation boundary.
2. Wrong nested type path: OptionsResponse.OptionData.YFOption does not exist;
YFOption is nested directly under OptionsResponse. Fix: reference
OptionsResponse.YFOption everywhere and remove the old private extension
in favour of the nonisolated makeContract(from:) factory method.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@StateObject is for objects SwiftUI creates and owns. DataStore.shared is
an existing singleton, so @ObservedObject is the correct wrapper.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Services/YahooFinanceClient.swift: Swift actor wrapping Yahoo Finance
unofficial APIs (price history, option chain, expirations, earnings date)
with 15-min in-memory cache
- Add Services/SignalEngine.swift: on-device IV Rank (rolling HV), SMA-50/200,
swing-level pivot support/resistance, Black-Scholes delta/theta, signal
strength scoring, and SHA-256 signal hash for change detection
- Add Services/RecommendationEngine.swift: strike selection (delta 0.15–0.40
target 0.25), expiration mapping per horizon (0DTE/1DTE/weekly/monthly),
rationale builder
- Add Services/DataStore.swift: @MainActor ObservableObject persisting all app
state as JSON files in the documents directory (UUID-keyed, no server IDs)
- Add Services/BackgroundRefreshManager.swift: BGAppRefreshTask registration +
foreground 15-min Timer; runs signal check per open position and fires local
notifications when hash changes or delta/profit thresholds are crossed
- Add Services/NotificationService.swift: UNUserNotificationCenter local
notification helper + badge count management
- Rewrite all 5 ViewModels to use DataStore + local services (no APIClient)
- Update Models to use UUID ids; remove snake_case CodingKeys (no network layer)
- Simplify AppDelegate: remove APNs, register BGTaskScheduler, start/stop timer
- Simplify NotificationPermissions/Handler: local notifications only, UUID
position deep-link
- Update Info.plist: replace remote-notification with fetch+processing background
modes, add BGTaskSchedulerPermittedIdentifiers
- Gut APIClient.swift and Endpoints.swift (no longer used)
- Update all Views to match new sync/async patterns and UUID-based models
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Xcode project was created inside the existing folder structure,
producing a second copy of all source files at the deeper nested path
that Xcode actually compiles. All fixes are now applied to both paths.
Changes:
- Add `import Combine` to nested ViewModels (Portfolio, Recommendations,
Positions, Alerts) and NotificationHandler — required for @Published
- Add `import UIKit` to NotificationPermissions — UIApplication is UIKit
- Rewrite APIClient to use `(any Encodable)?` instead of invalid
`(some Encodable)?` syntax; add encodeAny() helper to open existential
for JSONEncoder; remove private EmptyBody type
- Replace all `body: Optional<String>.none` / `Optional<EmptyBody>.none`
call sites with plain `nil` across all ViewModels and Views
- Sync all fixes between nested Xcode path and outer source path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `import Combine` to PortfolioViewModel, RecommendationsViewModel,
PositionsViewModel, AlertsViewModel, and NotificationHandler — required
for @Published and ObservableObject to resolve correctly in Swift
- Fix @MainActor isolation error in PositionDetailView: replace broken
default-parameter init (PositionsViewModel() in sync context) with
@StateObject private var localVM and an optional parentVM parameter
- Update OpenPositionsView call site to use new parentVM: label
- Fix var→let warning in PortfolioViewModel.add()
- Remove unused `old` variable in AppDelegate.registerDevice()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full-stack iOS options trading assistant:
- Python FastAPI backend with SQLite, APScheduler (15-min position monitor),
APNs push notifications, and yfinance market data integration
- Signal engine: IV Rank (rolling HV proxy), SMA-50/200, swing-based
support/resistance, earnings detection, signal strength scoring and
noise-resistant SHA hash for change detection
- Recommendation engine: covered call and cash-secured put strike/expiry
selection across 0DTE, 1DTE, weekly, and monthly horizons
- REST API: /devices, /portfolio, /recommendations, /positions, /signals, /alerts
- iOS SwiftUI app (iOS 17+): dashboard, recommendations, trades, portfolio,
and alerts tabs with push notification deep-linking
- Unit + integration tests for signal engine and API layer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>