An integrated study guide bridging algorithmic problem-solving and CFA financial modelling — where every calculation connects.
Green Sole tracks maize prices over 6 seasons. We must find the optimal buy/sell pairs to maximise profit using at most k = 2 transactions.
We build a 2D DP table where dp[i][j] = max profit using i transactions up to day j.
Key insight: maxDiff tracks the best "buy opportunity" seen so far, accounting for profits from previous transactions. This collapses a 3-loop O(kn²) solution into O(kn).
Time: O(k × n) · Space: O(k × n) — optimisable to O(n)
function maxProfit(k, prices) { // dp[i][j] = max profit with i transactions through day j let dp = Array.from({ length: k + 1 }, () => Array(prices.length).fill(0) ); for (let i = 1; i <= k; i++) { let maxDiff = -prices[0]; // best "buy" seen so far for (let j = 1; j < prices.length; j++) { // Option A: skip today | Option B: sell today dp[i][j] = Math.max( dp[i][j - 1], prices[j] + maxDiff ); // Update best buy: buy today vs buy before (with prev tx profit) maxDiff = Math.max( maxDiff, dp[i - 1][j] - prices[j] ); } } return dp[k][prices.length - 1]; } console.log(maxProfit(2, [100,180,260,310,40,535])); // → 705 ✅
The 705 algorithmic profit per cycle flows directly into the farm's financial model — added to final-year cash flows, feeding the NPV and IRR calculations below.
| Year | Base Farm Return | Algo Profit Added | Final Cash Flow |
|---|---|---|---|
| 0 | −500,000 | — | −500,000 |
| 1 | 120,000 | — | 120,000 |
| 2 | 150,000 | — | 150,000 |
| 3 | 180,000 | — | 180,000 |
| 4 | 220,000 | — | 220,000 |
| 5 | 260,000 | + 705 | 260,705 |
| Year (t) | Cash Flow | Discount Factor | Present Value |
|---|---|---|---|
| 0 | −500,000 | (1.15)⁰ = 1.0000 | −500,000.00 |
| 1 | 120,000 | (1.15)¹ = 1.1500 | 104,347.83 |
| 2 | 150,000 | (1.15)² = 1.3225 | 113,422.82 |
| 3 | 180,000 | (1.15)³ = 1.5209 | 118,324.00 |
| 4 | 220,000 | (1.15)⁴ = 1.7490 | 125,786.57 |
| 5 | 260,705 | (1.15)⁵ = 2.0114 | 129,617.34 |
A positive NPV means the project generates more value than its cost of capital. In CFA terms:
The risk premium of 5% already accounts for the agricultural uncertainty — so an NPV of ~91k above that hurdle is meaningful.
IRR is the discount rate at which NPV = 0. Compare it against the required return (hurdle rate). If IRR > hurdle rate, the project is viable.
function calculateIRR(cashFlows, guess = 0.1) { let rate = guess; for (let i = 0; i < 1000; i++) { let npv = 0; let derivative = 0; for (let t = 0; t < cashFlows.length; t++) { npv += cashFlows[t] / Math.pow((1 + rate), t); derivative -= t * cashFlows[t] / Math.pow((1 + rate), t + 1); } let newRate = rate - npv / derivative; if (Math.abs(newRate - rate) < 1e-6) break; rate = newRate; } return rate; } const flows = [-500000,120000,150000,180000,220000,260705]; console.log((calculateIRR(flows) * 100).toFixed(2) + "%"); // → ~18.91%
Modify any parameter to see how NPV changes in real time. Try changing the discount rate or the initial investment.