Module: DecisionAgent::Dsl::Operators::FinancialOperators
- Defined in:
- lib/decision_agent/dsl/operators/financial_operators.rb
Overview
Handles financial calculation operators: compound_interest, present_value, future_value, payment
Class Method Summary collapse
-
.compare_financial_result(actual, params) ⇒ Object
Compare financial result.
- .handle(op, actual_value, expected_value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
-
.parse_compound_interest_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse compound interest parameters.
- .parse_compound_interest_params_impl(value) ⇒ Object
-
.parse_future_value_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse future value parameters.
- .parse_future_value_params_impl(value) ⇒ Object
-
.parse_payment_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse payment parameters.
- .parse_payment_params_impl(value) ⇒ Object
-
.parse_present_value_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse present value parameters.
- .parse_present_value_params_impl(value) ⇒ Object
Class Method Details
.compare_financial_result(actual, params) ⇒ Object
Compare financial result
231 232 233 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 231 def self.compare_financial_result(actual, params) ConditionEvaluator.compare_financial_result(actual, params) end |
.handle(op, actual_value, expected_value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 8 def self.handle(op, actual_value, expected_value, param_cache: nil, param_cache_mutex: nil) case op when "compound_interest" # Calculates compound interest: A = P(1 + r/n)^(nt) return false unless actual_value.is_a?(Numeric) params = parse_compound_interest_params(expected_value, param_cache: param_cache, param_cache_mutex: param_cache_mutex) return false unless params principal = actual_value rate = params[:rate] periods = params[:periods] result = principal * ((1 + (rate / periods))**periods) if params[:result] (result.round(2) == params[:result].round(2)) else compare_financial_result(result, params) end when "present_value" # Calculates present value: PV = FV / (1 + r)^n return false unless actual_value.is_a?(Numeric) params = parse_present_value_params(expected_value, param_cache: param_cache, param_cache_mutex: param_cache_mutex) return false unless params future_value = actual_value rate = params[:rate] periods = params[:periods] present_value = future_value / ((1 + rate)**periods) if params[:result] (present_value.round(2) == params[:result].round(2)) else compare_financial_result(present_value, params) end when "future_value" # Calculates future value: FV = PV * (1 + r)^n return false unless actual_value.is_a?(Numeric) params = parse_future_value_params(expected_value, param_cache: param_cache, param_cache_mutex: param_cache_mutex) return false unless params present_value = actual_value rate = params[:rate] periods = params[:periods] future_value = present_value * ((1 + rate)**periods) if params[:result] (future_value.round(2) == params[:result].round(2)) else compare_financial_result(future_value, params) end when "payment" # Calculates loan payment: PMT = P * [r(1+r)^n] / [(1+r)^n - 1] return false unless actual_value.is_a?(Numeric) params = parse_payment_params(expected_value, param_cache: param_cache, param_cache_mutex: param_cache_mutex) return false unless params principal = actual_value rate = params[:rate] periods = params[:periods] return false if rate <= 0 || periods <= 0 payment = if rate.zero? principal / periods else principal * (rate * ((1 + rate)**periods)) / (((1 + rate)**periods) - 1) end if params[:result] (payment.round(2) == params[:result].round(2)) else compare_financial_result(payment, params) end end # Returns nil if not handled by this module end |
.parse_compound_interest_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse compound interest parameters
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 93 def self.parse_compound_interest_params(value, param_cache: nil, param_cache_mutex: nil) return nil unless value.is_a?(Hash) normalized = Base.normalize_params_to_hash(value, []) cache = param_cache mutex = param_cache_mutex if cache.nil? || mutex.nil? cache = ConditionEvaluator.instance_variable_get(:@param_cache) mutex = ConditionEvaluator.instance_variable_get(:@param_cache_mutex) end cache_key = Base.normalize_param_cache_key(normalized, "compound_interest") cached = cache[cache_key] return cached if cached mutex.synchronize do cache[cache_key] ||= parse_compound_interest_params_impl(normalized) end end |
.parse_compound_interest_params_impl(value) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 114 def self.parse_compound_interest_params_impl(value) rate = value[:rate] || value["rate"] periods = value[:periods] || value["periods"] return nil unless rate.is_a?(Numeric) && periods.is_a?(Numeric) && periods.positive? { rate: rate.to_f, periods: periods.to_f, result: value[:result] || value["result"], compare: value[:compare] || value["compare"], threshold: value[:threshold] || value["threshold"] } end |
.parse_future_value_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse future value parameters
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 163 def self.parse_future_value_params(value, param_cache: nil, param_cache_mutex: nil) return nil unless value.is_a?(Hash) normalized = Base.normalize_params_to_hash(value, []) cache = param_cache mutex = param_cache_mutex if cache.nil? || mutex.nil? cache = ConditionEvaluator.instance_variable_get(:@param_cache) mutex = ConditionEvaluator.instance_variable_get(:@param_cache_mutex) end cache_key = Base.normalize_param_cache_key(normalized, "future_value") cached = cache[cache_key] return cached if cached mutex.synchronize do cache[cache_key] ||= parse_future_value_params_impl(normalized) end end |
.parse_future_value_params_impl(value) ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 184 def self.parse_future_value_params_impl(value) rate = value[:rate] || value["rate"] periods = value[:periods] || value["periods"] return nil unless rate.is_a?(Numeric) && periods.is_a?(Numeric) && periods.positive? { rate: rate.to_f, periods: periods.to_f, result: value[:result] || value["result"] } end |
.parse_payment_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse payment parameters
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 197 def self.parse_payment_params(value, param_cache: nil, param_cache_mutex: nil) return nil unless value.is_a?(Hash) normalized = Base.normalize_params_to_hash(value, []) cache = param_cache mutex = param_cache_mutex if cache.nil? || mutex.nil? cache = ConditionEvaluator.instance_variable_get(:@param_cache) mutex = ConditionEvaluator.instance_variable_get(:@param_cache_mutex) end cache_key = Base.normalize_param_cache_key(normalized, "payment") cached = cache[cache_key] return cached if cached mutex.synchronize do cache[cache_key] ||= parse_payment_params_impl(normalized) end end |
.parse_payment_params_impl(value) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 218 def self.parse_payment_params_impl(value) rate = value[:rate] || value["rate"] periods = value[:periods] || value["periods"] return nil unless rate.is_a?(Numeric) && periods.is_a?(Numeric) && periods.positive? { rate: rate.to_f, periods: periods.to_f, result: value[:result] || value["result"] } end |
.parse_present_value_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object
Parse present value parameters
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 129 def self.parse_present_value_params(value, param_cache: nil, param_cache_mutex: nil) return nil unless value.is_a?(Hash) normalized = Base.normalize_params_to_hash(value, []) cache = param_cache mutex = param_cache_mutex if cache.nil? || mutex.nil? cache = ConditionEvaluator.instance_variable_get(:@param_cache) mutex = ConditionEvaluator.instance_variable_get(:@param_cache_mutex) end cache_key = Base.normalize_param_cache_key(normalized, "present_value") cached = cache[cache_key] return cached if cached mutex.synchronize do cache[cache_key] ||= parse_present_value_params_impl(normalized) end end |
.parse_present_value_params_impl(value) ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/decision_agent/dsl/operators/financial_operators.rb', line 150 def self.parse_present_value_params_impl(value) rate = value[:rate] || value["rate"] periods = value[:periods] || value["periods"] return nil unless rate.is_a?(Numeric) && periods.is_a?(Numeric) && periods.positive? { rate: rate.to_f, periods: periods.to_f, result: value[:result] || value["result"] } end |