Functional Weave
Code in Rust

invest.drawdown-sustainability@1.0.1

vectors.json

17,360 bytes · view raw

[
 {
  "name": "£1,000 drawn at £300 a year with no growth: three full years and a £100 fourth",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 30000,
    "currency": "GBP"
   },
   0,
   0,
   10
  ],
  "expect": {
   "fullYears": 3,
   "exhausted": true,
   "totalWithdrawn": {
    "minor": 100000,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 0,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 100000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 30000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 70000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 70000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 30000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 40000,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 40000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 30000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 10000,
      "currency": "GBP"
     }
    },
    {
     "year": 4,
     "opening": {
      "minor": 10000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 0,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "withdrawal first, then 10% growth on what is left (not growth first)",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 10000,
    "currency": "GBP"
   },
   1000,
   0,
   3
  ],
  "expect": {
   "fullYears": 3,
   "exhausted": false,
   "totalWithdrawn": {
    "minor": 30000,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 96690,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 100000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 9000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 99000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 99000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 8900,
      "currency": "GBP"
     },
     "closing": {
      "minor": 97900,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 97900,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 8790,
      "currency": "GBP"
     },
     "closing": {
      "minor": 96690,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "a withdrawal equal to the growth on the remainder lasts for ever",
  "args": [
   {
    "minor": 110000,
    "currency": "GBP"
   },
   {
    "minor": 10000,
    "currency": "GBP"
   },
   1000,
   0,
   5
  ],
  "expect": {
   "fullYears": 5,
   "exhausted": false,
   "totalWithdrawn": {
    "minor": 50000,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 110000,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 110000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 10000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 110000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 110000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 10000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 110000,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 110000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 10000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 110000,
      "currency": "GBP"
     }
    },
    {
     "year": 4,
     "opening": {
      "minor": 110000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 10000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 110000,
      "currency": "GBP"
     }
    },
    {
     "year": 5,
     "opening": {
      "minor": 110000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 10000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 110000,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "an income rising 10% a year runs out in the fifth year",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 20000,
    "currency": "GBP"
   },
   0,
   1000,
   10
  ],
  "expect": {
   "fullYears": 4,
   "exhausted": true,
   "totalWithdrawn": {
    "minor": 100000,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 0,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 100000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 20000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 80000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 80000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 22000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 58000,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 58000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 24200,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 33800,
      "currency": "GBP"
     }
    },
    {
     "year": 4,
     "opening": {
      "minor": 33800,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 26620,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 7180,
      "currency": "GBP"
     }
    },
    {
     "year": 5,
     "opening": {
      "minor": 7180,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 7180,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 0,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "growth is rounded to the penny every year",
  "args": [
   {
    "minor": 10001,
    "currency": "GBP"
   },
   {
    "minor": 3333,
    "currency": "GBP"
   },
   333,
   0,
   10
  ],
  "expect": {
   "fullYears": 3,
   "exhausted": true,
   "totalWithdrawn": {
    "minor": 10352,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 0,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 10001,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 3333,
      "currency": "GBP"
     },
     "growth": {
      "minor": 222,
      "currency": "GBP"
     },
     "closing": {
      "minor": 6890,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 6890,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 3333,
      "currency": "GBP"
     },
     "growth": {
      "minor": 118,
      "currency": "GBP"
     },
     "closing": {
      "minor": 3675,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 3675,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 3333,
      "currency": "GBP"
     },
     "growth": {
      "minor": 11,
      "currency": "GBP"
     },
     "closing": {
      "minor": 353,
      "currency": "GBP"
     }
    },
    {
     "year": 4,
     "opening": {
      "minor": 353,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 353,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 0,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "a pot that reaches exactly zero on a full withdrawal counts that year",
  "args": [
   {
    "minor": 20000,
    "currency": "GBP"
   },
   {
    "minor": 10000,
    "currency": "GBP"
   },
   0,
   0,
   5
  ],
  "expect": {
   "fullYears": 2,
   "exhausted": true,
   "totalWithdrawn": {
    "minor": 20000,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 0,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 20000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 10000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 10000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 0,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "a market halving every year",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 10000,
    "currency": "GBP"
   },
   -5000,
   0,
   10
  ],
  "expect": {
   "fullYears": 3,
   "exhausted": true,
   "totalWithdrawn": {
    "minor": 33750,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 0,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 100000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": -45000,
      "currency": "GBP"
     },
     "closing": {
      "minor": 45000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 45000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": -17500,
      "currency": "GBP"
     },
     "closing": {
      "minor": 17500,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 17500,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 10000,
      "currency": "GBP"
     },
     "growth": {
      "minor": -3750,
      "currency": "GBP"
     },
     "closing": {
      "minor": 3750,
      "currency": "GBP"
     }
    },
    {
     "year": 4,
     "opening": {
      "minor": 3750,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 3750,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 0,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "one year modelled",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "GBP"
   },
   500,
   0,
   1
  ],
  "expect": {
   "fullYears": 1,
   "exhausted": false,
   "totalWithdrawn": {
    "minor": 1000,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 103950,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 100000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 1000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 4950,
      "currency": "GBP"
     },
     "closing": {
      "minor": 103950,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "an empty pot pays nothing and is exhausted at once",
  "args": [
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "GBP"
   },
   500,
   0,
   5
  ],
  "expect": {
   "fullYears": 0,
   "exhausted": true,
   "totalWithdrawn": {
    "minor": 0,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 0,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 0,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 0,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 0,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "a falling withdrawal: 50% less each year",
  "args": [
   {
    "minor": 10000,
    "currency": "GBP"
   },
   {
    "minor": 4000,
    "currency": "GBP"
   },
   0,
   -5000,
   5
  ],
  "expect": {
   "fullYears": 5,
   "exhausted": false,
   "totalWithdrawn": {
    "minor": 7750,
    "currency": "GBP"
   },
   "closingBalance": {
    "minor": 2250,
    "currency": "GBP"
   },
   "schedule": [
    {
     "year": 1,
     "opening": {
      "minor": 10000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 4000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 6000,
      "currency": "GBP"
     }
    },
    {
     "year": 2,
     "opening": {
      "minor": 6000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 2000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 4000,
      "currency": "GBP"
     }
    },
    {
     "year": 3,
     "opening": {
      "minor": 4000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 1000,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 3000,
      "currency": "GBP"
     }
    },
    {
     "year": 4,
     "opening": {
      "minor": 3000,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 500,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 2500,
      "currency": "GBP"
     }
    },
    {
     "year": 5,
     "opening": {
      "minor": 2500,
      "currency": "GBP"
     },
     "withdrawal": {
      "minor": 250,
      "currency": "GBP"
     },
     "growth": {
      "minor": 0,
      "currency": "GBP"
     },
     "closing": {
      "minor": 2250,
      "currency": "GBP"
     }
    }
   ]
  }
 },
 {
  "name": "a negative pot is an error",
  "args": [
   {
    "minor": -1,
    "currency": "GBP"
   },
   {
    "minor": 1000,
    "currency": "GBP"
   },
   0,
   0,
   5
  ],
  "expectError": "pot must be whole minor units, 0 or more"
 },
 {
  "name": "a zero withdrawal is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   0,
   0,
   5
  ],
  "expectError": "annualWithdrawal must be whole minor units greater than zero"
 },
 {
  "name": "a fractional withdrawal is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 10.5,
    "currency": "GBP"
   },
   0,
   0,
   5
  ],
  "expectError": "annualWithdrawal must be whole minor units greater than zero"
 },
 {
  "name": "growth below -100% is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 100,
    "currency": "GBP"
   },
   -10001,
   0,
   5
  ],
  "expectError": "annualGrowthBasisPoints must be a whole number, -10000 or more"
 },
 {
  "name": "an increase below -100% is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 100,
    "currency": "GBP"
   },
   0,
   -10001,
   5
  ],
  "expectError": "withdrawalIncreaseBasisPoints must be a whole number, -10000 or more"
 },
 {
  "name": "zero years is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 100,
    "currency": "GBP"
   },
   0,
   0,
   0
  ],
  "expectError": "maxYears must be a whole number from 1 to 100"
 },
 {
  "name": "101 years is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 100,
    "currency": "GBP"
   },
   0,
   0,
   101
  ],
  "expectError": "maxYears must be a whole number from 1 to 100"
 },
 {
  "name": "fractional years are an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 100,
    "currency": "GBP"
   },
   0,
   0,
   2.5
  ],
  "expectError": "maxYears must be a whole number from 1 to 100"
 },
 {
  "name": "a withdrawal in another currency is an error",
  "args": [
   {
    "minor": 1000,
    "currency": "GBP"
   },
   {
    "minor": 100,
    "currency": "EUR"
   },
   0,
   0,
   5
  ],
  "expectError": "currency mismatch: GBP and EUR"
 }
]