Closed thearabbit closed 3 years ago
Not presently (IIRC), but I could probably just add a default to make it optional
thanks for your reply, something I don't know to set maxIterations
because the Goal
is dynamic???
I would like to try this goal-seek
to adjust Total Payment of PMT Function
for Annuity Loan Schedule
.
I'm not sure I understand. Could you provide an example?
On Mon, Apr 19, 2021, 11:45 PM Yuom Theara @.***> wrote:
thanks for your reply, something I don't know to set maxIterations because the Goal is dynamic???
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/adam-hanna/goal-seek/issues/8#issuecomment-822990569, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABJPMFWCLTCYZFFHBE5I3TTTJUIJNANCNFSM43HKTS5A .
Excuse me for late. This is my example (Sorry my English not good)
### PMT Monthly
- Rate: 3%
- Term: 36
- Loan amount: 20,000.00
- Total payment (PMT Function): PMT(Rate, Term,-Loan amount) = 916.08
-
**NOTE:**
- Interest payment = calculate by declining method
- Principal payment = Total payment - Interest payment
And then I would like to set ending balance Cell G46
closely to Zero (0) by changing total payment (PMT) Cell D11
value
### Goal seek
- Set cell: G46
- To value: 0
- By changing cell: $D$11
- ------------
- Result = 921.05
My JS
Code (I base on Meteor JS + Vue
)
import { pmt } from 'financial'
import _ from 'lodash'
import dayjs from 'dayjs'
import goalSeek from 'goal-seek'
// ---------------------------
let rate = 3, term = 36, amount = 20000, disDate = '2021-01-15
let totalPayment = pmt(rate / 100, term, -amount)
totalPayment = _.round(totalPayment, 2) // 916.08
const result = goalSeek({
fn: checkEndingBalance,
fnParams: [{ rate, term, amount, disDate }, totalPayment],
percentTolerance: 1,
maxIterations: 1000000,
maxStep: 1,
goal: 0,
independentVariableIdx: 1,
})
// Result => ???? (failed to converge)
// ---------------------------
function checkEndingBalance(params, totalPayment) {
const { rate, term, amount, disDate } = params
try {
let schedules = [
{
no: 0,
date: disDate,
day: 0,
totalPayment: 0,
principal: 0,
interest: 0,
balance: amount,
},
]
for (i = 1; i <= term; i++) {
let preSchedule = schedules[i - 1]
let dueDate = dayjs(disDate, 'YYYY-MM-DD').add(i, 'month')
let day = dueDate.diff(preSchedule.date, 'day')
let interest = preSchedule.balance * day * (rate / 100 / 30)
interest = _.round(interest, 2)
let principal = totalPayment - interest
let balance = preSchedule.balance - principal
schedules.push({
no: i,
date: dueDate.format('YYYY-MM-DD'),
day: day,
totalPayment,
principal,
interest,
balance,
})
}
const endingBalance = schedules[term].balance
console.log('Ending Balance: ', endingBalance)
return endingBalance
} catch (e) {
console.log(e)
}
}
variable/prop
don't need in Goal Seek Function
:closely/nearly
the goalfn() prop
such as the schedules
(Don't need do again)Thanks for your package and helping 💯
Thanks for the example, and your English is great! :)
I definitely agree that I could make some of those inputs optional, but that means that I would need to come up with sane defaults, programmatically. Currently, I put that burden on the user.
From your example, I noticed that the current parameters of the function may not be sufficient for some users. For example, in your case, you had a stated goal of 0, with a percent tolerance of 1. However, 1% of 0 is still 0, so the function will never converge. Therefore, I made percentTolerance optional and added a new optional param, customToleranceFn?: (arg0: number) => boolean;
.
If you update your dep to version 0.1.4 you can try the following:
import { pmt } from 'financial'
import _ from 'lodash'
import dayjs from 'dayjs'
import goalSeek from 'goal-seek'
// ---------------------------
let rate = 3, term = 36, amount = 20000, disDate = '2021-01-15'
let totalPayment = pmt(rate / 100, term, -amount)
totalPayment = _.round(totalPayment, 2) // 916.08
const customToleranceFn = (x) => {
return x <= 0.01
}
const result = goalSeek({
fn: checkEndingBalance,
fnParams: [{ rate, term, amount, disDate }, totalPayment],
customToleranceFn,
maxIterations: 1000000,
maxStep: 0.0005,
goal: 0.01,
independentVariableIdx: 1,
})
// ---------------------------
function checkEndingBalance(params, totalPayment) {
const { rate, term, amount, disDate } = params
try {
let schedules = [
{
no: 0,
date: disDate,
day: 0,
totalPayment: 0,
principal: 0,
interest: 0,
balance: amount,
},
]
for (let i = 1; i <= term; i++) {
let preSchedule = schedules[i - 1]
let dueDate = dayjs(disDate, 'YYYY-MM-DD').add(i, 'month')
let day = dueDate.diff(preSchedule.date, 'day')
let interest = preSchedule.balance * day * (rate / 100 / 30)
interest = _.round(interest, 2)
let principal = totalPayment - interest
let balance = preSchedule.balance - principal
schedules.push({
no: i,
date: dueDate.format('YYYY-MM-DD'),
day: day,
totalPayment,
principal,
interest,
balance,
})
}
const endingBalance = schedules[term].balance
console.log('Ending Balance: ', endingBalance)
return endingBalance
} catch (e) {
console.log(e)
}
}
console.log(result) // result 921.0457222230434
thanks for your helping. I have some questions:
0
? if true you could NOTE
on document.percentTolerance & customToleranceFn
, with have 2 data types
Ex: percentTolerance: Number | Fn (Boolean) While loop/Do...While
to check until finding the result. For my case I am not sure to set it, because sometime the Loan Term
is very long term. So I must to set maxIterations = big number
as default?Very thanks again 👍
- Goal: Can't set
0
? if true you couldNOTE
on document.
Good point. I should make a note of this in the documentation.
- Why don't use the same param name
percentTolerance & customToleranceFn
, with have 2 data types Ex: percentTolerance: Number | Fn (Boolean)
I guess I could have but I personally don't like overloading types. Just a personal preference of mine.
- maxIterations: Why you don't use
While loop/Do...While
to check until finding the result. For my case I am not sure to set it, because sometime theLoan Term
is very long term. So I must to setmaxIterations = big number
as default?
maxIterations
is necessary because somethings the stepsize is too large and it gets stuck in an infinite loop. At some point, the program needs to give up.
Thanks agin, Now It work fine for this case. If have any problem of other cases, I will create new issue!!!!
Great!! Glad it's working!
On Thu, Apr 22, 2021, 5:58 PM Yuom Theara @.***> wrote:
Thanks agin, Now It work fine for this case. If have any problem of other cases, I will create new issue!!!!
— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/adam-hanna/goal-seek/issues/8#issuecomment-825275137, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABJPMFRPZJPH7XFLAKGTMOLTKCZ23ANCNFSM43HKTS5A .