DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on • Edited on

เขียนโปรแกรม (ด้วย Go) สร้างตารางการผ่อนบ้านแบบลดต้นลดดอก

ช่วงนี้กำลังตัดสินใจเลือกสถาบันการเงินที่จะทำ Refinance บ้าน จริงๆก็มีหลายที่แจกตาราง Excel ให้ลองคำนวณดูว่าถ้ามีดอกเบี้ยเท่านี้ จ่ายเงินแต่ละงวดเท่านี้ จะเป็นดอกเบี้ยเท่าไหร่ ตัดเงินต้นเท่าไหร่ และ ผ่อนกี่งวดถึงจะหมด

แต่ว่าเราก็อยากทำความเข้าใจสูตรด้วยและเราเขียน script สำหรับ Excel หรือของโปรแกรม spread sheet เจ้าอื่นๆไม่เป็น ดังนั้นจึงลองมาทำความเข้าใจแล้วเขียนด้วย Go เพื่อให้เราปรับแต่งตัวแปรต่างๆได้เองง่ายๆ

ทีนี้ตอนนี้ก็เลยพยายามแกะสูตรที่ทางธนาคารใช้ กับเว็บอื่นๆใช้ พบว่าเจอสูตรคำนวณดอกเบี้ยอยู่สองแบบ

1) ธนาคารสมมติให้ชื่อว่าธนาคาร K บอกว่าถ้ามารีไฟแนนซ์ด้วยภายใน 3 ปีแรกจะให้ดอกเบี้ยที่ 1.75%, 2.20% และ MRR-1.75% (ประมาณ 4.30%) ผ่อนขั้นต่ำงวดละ 27,600 บาท ซึ่งพอแกะออกมาดูพบว่าเขาคำนวณดอกเบี้ยในแต่ละเดือนแบบนี้

ดอกเบี้ยเดือนนี้ = เงินต้นที่เหลือจากเดือนก่อน * อัตราดอกเบี้ย / 12

ตัวอย่างเช่น ถ้ามีเงินต้นที่เหลือ 4,900,000 และอัตราดอกเบี้ย 1.75% จะได้ดอกที่ต้องจ่ายงวดที่จะถึงเป็นเงิน

4,900,000 * 0.0175 / 12 == 7145.83

ปัดเศษให้เหลือทศนิยมสองตำแหน่ง เช่น 7145.833 ปัดเป็น 7145.83 ถ้าเป็น 7145.836 ปัดเป็น 7145.84

2) กับอีกสูตรที่เห็นทางผู้ให้บริการทีปรึกษาการรีไฟแนนซ์ใช้คือ

ดอกเบี้ยเดือนนี้ = เงินต้นที่เหลือจากเดือนก่อน * อัตราดอกเบี้ย / 365 * 30

ตัวอย่างเช่น ถ้ามีเงินต้นที่เหลือ 4,900,000 และอัตราดอกเบี้ย 1.75% จะได้ดอกที่ต้องจ่ายงวดที่จะถึงเป็นเงิน

4,900,000 * 0.0175 / 365 * 30 == 7047.95

สิ่งที่ผมอยากได้คือโปรแกรมที่สร้างตารางที่บอกรายละเอียดแต่ละ column แบบนี้

เดือนที่ | วงเงินกู้คงเหลือ | อัตราดอกเบี้ย | อัตราผ่อนต่อเดือน | ชำระดอกเบี้ย | ชำระเงินต้น | เงินต้นคงเหลือ
Enter fullscreen mode Exit fullscreen mode

ทีนี้มาดูโค้ด Go ที่ผมเขียนเอาไว้กัน เริ่มจากผมออกแบบ struct ที่ชื่อว่า Record ให้เก็บรายละเอียดของข้อมูลที่คำนวณได้แต่ละเดือนแบบนี้

type Record struct {
    Month                int
    LoanSubunits         int
    MonthPaidSubunits    int
    InterestRate         float64
    InterestPaidSubunits int
    LoanPaidSubunits     int
    RestLoanSubunits     int
}
Enter fullscreen mode Exit fullscreen mode

จะเห็นว่าค่าไหนก็ตามที่เก็บจำนวนเงิน หมดใช้ประเภทข้อมูลเป็นจำนวนเต็มหมดเลยและเก็บเป็น subunits ซึ่งเป็นหน่วยที่เล็กสุดของหน่วยค่าเงินหลัก เช่น บาท subunits ก็คือหน่วย สตางค์ ที่เราใช้ int เก็บเพราะทำให้เราไม่มีปัญหาเรื่องความแม่นยำของตัวเลขทศนิยมเหมือนที่เราใช้ float64 และช่วยให้เราคำนวณตอนปัดเศษง่ายอีกด้วย

ต่อไปเนื่องจากผมมีสูตรการคำนวณดอกเบี้ยถึงสองสูตร ดังนั้นจึงออกแบบเป็น type ของฟังก์ชันเพื่อให้เรากำหนดพารามิเตอร์ส่งให้กับฟังก์ชันที่เราเขียนในการสร้างตารางได้ดังนี้

type interestCalcFunc func(loanSubunits int, interestRest float64) int
Enter fullscreen mode Exit fullscreen mode

ซึ่งก็รับค่าจำนวนเงินต้นที่ต้องการคำนวณ กับอัตราดอกเบี้ยเข้าไป

ส่วนตัว 2 ฟังก์ชันที่ใช้คำนวณในแบบที่ 1 และ 2 ทำไว้แบบนี้

func ksInterestCalc(loanSubunits int, interestRate float64) int {
    return int(math.Round(float64(loanSubunits) * interestRate / (12.0)))
}

func rInterestCalc(loanSubunits int, interestRest float64) int {
    return int(math.Round(float64(loanSubunits) * interestRest / 365.0 * 30))
}
Enter fullscreen mode Exit fullscreen mode

ซึ่งก็เป็นสูตรแบบที่บอกไปแล้ว แต่น่าจะเห็นวิธีที่ผมใช้คือตอนคำนวณ เราแปลงให้เป็น float64 ก่อน หลังจากนั้นเราปัดเศษด้วย math.Round แล้วแปลงเป็น int อีกที การที่เราใช้ subunits ก็ช่วยให้เราใช้ math.Round ปัดเศษในทศนิยมตำแหน่งที่ 2 ให้เราได้โดยใช้ฟังก์ชัน math.Round ที่จะปัดเศษของทศนิยมเป็นจำนวนเต็มนั่นเอง เช่นถ้าเรามีเลข 714583.333 จากการคำนวณ ก็จะปัดเป็น 714583 ซึ่งก็คือ 7145.83 บาทนั่นเอง

ต่อไปตัวฟังก์ชันที่ใช้สร้างตารางนั้นผมทำให้มันเป็นในลักษณะของ CSV คือใช้ comma คั่น ซึ่งสะดวกในการ import ไปดูต่อในพวกโปรแกรม spread sheet ต่างๆ

ตัวโค้ดเป็นแบบนี้

func printMonthlyInterest(paidPerMonth int, interestRate float64, restLoanSubunits int, from, to int, interestFn interestCalcFunc) Record {
    var r Record
    r.RestLoanSubunits = restLoanSubunits
    for i := from; i <= to; i++ {
        r = Record{
            Month:             i,
            LoanSubunits:      r.RestLoanSubunits,
                        MonthPaidSubunits: paidPerMonth,
                        InterestRate: interestRate,
        }

        r.InterestPaidSubunits = interestFn(r.LoanSubunits, interestRate)
        r.LoanPaidSubunits = r.MonthPaidSubunits - r.InterestPaidSubunits
        r.RestLoanSubunits = r.LoanSubunits - (r.MonthPaidSubunits - r.InterestPaidSubunits)

        fmt.Printf("%d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
            r.Month,
            float64(r.LoanSubunits)/100.0,
            r.InterestRate*100.0,
            float64(r.MonthPaidSubunits)/100.0,
            float64(r.InterestPaidSubunits)/100.0,
            float64(r.LoanPaidSubunits)/100.0,
            float64(r.RestLoanSubunits)/100.0,
        )
    }
    return r
}
Enter fullscreen mode Exit fullscreen mode

ถ้าดูจาก signature ของฟังก์ชัน

func printMonthlyInterest(paidPerMonth int, interestRate float64, restLoanSubunits int, from, to int, interestFn interestCalcFunc) Record
Enter fullscreen mode Exit fullscreen mode

จะเห็นว่ารับค่าเงินที่จะต้องจ่ายต่องวด รับค่าอัตราดอกเบี้ย รับค่าของเงินต้นที่เหลือก่อนหน้า และเลขระบุว่าจากงวดไหนถึงงวดไหน ตามด้วยฟังก์ชันในการคำนวณอัตราดอกเบี้ย

จากนั้นก็สร้างตัวแปร var r Record มาค่านึงเพื่อกำหนดจำนวนเงินที่เหลือของงวดก่อน ซึ่งในแต่ละรอบจำเป็นต้องเอาเงินงวดก่อนมาใช้คำนวณดังนั้นเราก็เลยต้องสร้างมาเก็บไว้ก่อน

ทีนี้ในแต่ละรอบของลูปที่วนจากงวด from ไปงวด to นั้นเราก็จะคำนวนค่าต่างๆในงวดที่ i แบบนี้

r = Record{
        Month:             i,
        LoanSubunits:      r.RestLoanSubunits,
        MonthPaidSubunits: paidPerMonth,
        InterestRate: interestRate,
}

r.InterestPaidSubunits = interestFn(r.LoanSubunits, interestRate)
r.LoanPaidSubunits = r.MonthPaidSubunits - r.InterestPaidSubunits
r.RestLoanSubunits = r.LoanSubunits - r.LoanPaidSubunits
Enter fullscreen mode Exit fullscreen mode

ดอกเบี้ยที่ต้องจ่ายก็ใช้ฟังก์ชันที่ส่งมาในการคำนวณ, เงินต้นที่จ่ายก็คือค่างวดหักดอกเบี้ย และ เงินต้นที่เหลือก็คือเงินต้นก่อนหน้า ลบเงินต้นที่หักจริงๆหลักจากตัดดอกแล้ว

ต่อไปก็เป็นแค่การแสดงผลโดยใช้ %.2f ในการให้แสดงทศนิยม 2 ตำแหน่ง และอะไรที่เป็น subunits อยู่เราก็จัดการหาร 100.0 ก่อน

ตัวอย่างการเอาไปใช้ถ้าเรามีเงินต้นเหลือ 4,900,000 อยากเห็นตารางการผ่อน 12 งวดแรกที่อัตราดอกเบี้ย 1.75% ก็เรียกใช้งานได้แบบนี้

func main() {
    printMonthlyInterest(31_900_00, 0.0175, 4_900_000_00, 1, 12, ksInterestCalc)
}
Enter fullscreen mode Exit fullscreen mode

ทีนี้ถ้าเราอยากคำนวณต่องวดที่ 13 ถึง 24 ก็ให้รับค่า record สุดท้ายที่รีเทิร์นกลับมาจากการเรียกครั้งแรกแล้วเอาเงินต้นที่เหลือส่งเป็นอาร์กิวเม้นให้การเรียกครั้งถัดไปเช่น

func main() {
        var r Record
        r = printMonthlyInterest(31_900_00, 0.0175, 4_900_000_00, 1, 12, ksInterestCalc)
        printMonthlyInterest(31_900_00, 0.0220, r.RestLoanSubunits, 13, 24, ksInterestCalc)
}
Enter fullscreen mode Exit fullscreen mode

ลองรันดูก็จะได้ตารางแบบนี้

1, 4900000.00, 1.75, 31900.00, 7145.83, 24754.17, 4875245.83
2, 4875245.83, 1.75, 31900.00, 7109.73, 24790.27, 4850455.56
3, 4850455.56, 1.75, 31900.00, 7073.58, 24826.42, 4825629.14
4, 4825629.14, 1.75, 31900.00, 7037.38, 24862.62, 4800766.52
5, 4800766.52, 1.75, 31900.00, 7001.12, 24898.88, 4775867.64
6, 4775867.64, 1.75, 31900.00, 6964.81, 24935.19, 4750932.45
7, 4750932.45, 1.75, 31900.00, 6928.44, 24971.56, 4725960.89
8, 4725960.89, 1.75, 31900.00, 6892.03, 25007.97, 4700952.92
9, 4700952.92, 1.75, 31900.00, 6855.56, 25044.44, 4675908.48
10, 4675908.48, 1.75, 31900.00, 6819.03, 25080.97, 4650827.51
11, 4650827.51, 1.75, 31900.00, 6782.46, 25117.54, 4625709.97
12, 4625709.97, 1.75, 31900.00, 6745.83, 25154.17, 4600555.80
13, 4600555.80, 2.20, 31900.00, 8434.35, 23465.65, 4577090.15
14, 4577090.15, 2.20, 31900.00, 8391.33, 23508.67, 4553581.48
15, 4553581.48, 2.20, 31900.00, 8348.23, 23551.77, 4530029.71
16, 4530029.71, 2.20, 31900.00, 8305.05, 23594.95, 4506434.76
17, 4506434.76, 2.20, 31900.00, 8261.80, 23638.20, 4482796.56
18, 4482796.56, 2.20, 31900.00, 8218.46, 23681.54, 4459115.02
19, 4459115.02, 2.20, 31900.00, 8175.04, 23724.96, 4435390.06
20, 4435390.06, 2.20, 31900.00, 8131.55, 23768.45, 4411621.61
21, 4411621.61, 2.20, 31900.00, 8087.97, 23812.03, 4387809.58
22, 4387809.58, 2.20, 31900.00, 8044.32, 23855.68, 4363953.90
23, 4363953.90, 2.20, 31900.00, 8000.58, 23899.42, 4340054.48
24, 4340054.48, 2.20, 31900.00, 7956.77, 23943.23, 4316111.25
Enter fullscreen mode Exit fullscreen mode

เสร็จแล้วเรียบร้อยโค้ดสำหรับใช้สร้างตารางอัตราดอกเบี้ย จากนี้ก็เอาไปใช้เปลี่ยนตัวแปรต่างๆตามที่แต่ละสถาบันการเงินสามารถให้ได้ แล้วก็ตัดสินใจว่าจะรีไฟแนนซ์ไปที่ไหนคุ้มและเหมาะสมกับเราต่อไป

Buy Me A Coffee

Top comments (0)