@@ -217,10 +217,11 @@ def solve_rate(
217217 UnsolvableError: If no rate can be found within bounds.
218218
219219 Notes:
220+ - If called after solve_value, uses the existing profile (if it has a 'factor' column)
221+ and sets all is_known to True to ensure validation passes for SOLVE_RATE mode.
222+ - Always assigns day count factors based on the provided convention, as it may differ
223+ from the convention used in solve_value.
220224 - Uses scipy.optimize.brentq for root-finding within [-0.9999, upper_bound].
221- - Upper bound is configurable to handle extreme APRs (e.g., usurious loans > 1000%).
222- - Very large upper bounds (e.g., > 100.0) may slow convergence or cause
223- numerical issues.
224225 - For USAppendixJ, the periodic rate is annualized by multiplying by periods_in_year.
225226 """
226227 if upper_bound <= 0.0 :
@@ -230,11 +231,20 @@ def solve_rate(
230231 if self ._is_bespoke_profile :
231232 if not isinstance (self .profile , pd .DataFrame ) or self .profile .empty :
232233 raise ValidationError ("Bespoke profile must be a non-empty DataFrame" )
233- cash_flows = self .profile
234+ cash_flows = self .profile . copy ()
234235 else :
235- if not self ._series :
236- raise ValidationError ("No cash flow series provided" )
237- cash_flows = self ._build_profile (start_date )
236+ # Check if profile exists and has a 'factor' column (indicating solve_value was called)
237+ if (self .profile is not None and
238+ isinstance (self .profile , pd .DataFrame ) and
239+ not self .profile .empty and
240+ ColumnExtras .FACTOR .value in self .profile .columns ):
241+ cash_flows = self .profile .copy () # Use existing profile
242+ # Set all is_known to True to pass SOLVE_RATE validation
243+ cash_flows [Column .IS_KNOWN .value ] = True
244+ else :
245+ if not self ._series :
246+ raise ValidationError ("No cash flow series provided" )
247+ cash_flows = self ._build_profile (start_date )
238248
239249 sort_by = SortColumn .POST_DATE if convention .use_post_dates else SortColumn .VALUE_DATE
240250 cash_flows = self ._sort_cash_flows (cash_flows , sort_by = sort_by )
@@ -244,7 +254,7 @@ def solve_rate(
244254 mode = ValidationMode .SOLVE_RATE
245255 )
246256
247- # Assign day count factors
257+ # Assign day count factors based on the provided convention
248258 cash_flows = self ._assign_factors (cash_flows , convention )
249259
250260 # Define NFV function for root-finding
@@ -387,8 +397,8 @@ def build_schedule(
387397 continue # Skip charges
388398 amount = row [Column .AMOUNT .value ]
389399 interest = row [ColumnExtras .INTEREST .value ]
390- capital = amount - interest
391- capital_balance += interest + amount # Amount includes sign (negative for advances)
400+ capital = amount + interest
401+ capital_balance += interest + amount
392402
393403 schedule .at [
394404 idx , ColumnExtras .CAPITAL .value
0 commit comments