squiggle/src/models/EAFunds.re

226 lines
5.6 KiB
ReasonML
Raw Normal View History

2020-02-10 20:37:12 +00:00
module Data = {
type fund =
| ANIMAL_WELFARE
| GLOBAL_HEALTH
| LONG_TERM_FUTURE
| META;
type group =
| Fund(fund)
| All;
type output =
| DONATIONS
| PAYOUTS;
type fundWithInfo = {
group,
name: string,
existingDonations: option(float),
existingPayouts: option(float),
};
let makeFundWithInfo = (name, group, existingDonations, existingPayouts) => {
group,
name,
existingDonations,
existingPayouts,
};
let funds = [|
makeFundWithInfo(
"Animal Welfare Fund",
Fund(ANIMAL_WELFARE),
Some(4000.0),
Some(10.0),
),
makeFundWithInfo(
"Global Health Fund",
Fund(GLOBAL_HEALTH),
Some(4000.0),
Some(10.0),
),
makeFundWithInfo(
"Long Term Future Fund",
Fund(LONG_TERM_FUTURE),
Some(4000.0),
Some(10.0),
),
makeFundWithInfo(
"Meta Fund",
Fund(ANIMAL_WELFARE),
Some(4000.0),
Some(10.0),
),
makeFundWithInfo("All", All, None, None),
|];
};
module Model = {
open Data;
let currentYear = 2020.;
let firstYearStdDev = 0.2;
type yearlyNumericDiff = {
meanDiff: float,
stdDiff: float,
};
let yearlyMeanGrowthRateIfNotClosed = (group: group): yearlyNumericDiff => {
{meanDiff: 1.1, stdDiff: 1.1};
};
let calculateDifference =
(currentValue, dateTime, currentDateTime, y: yearlyNumericDiff) => {
let yearDiff = MomentRe.diff(dateTime, currentDateTime, `days) /. 365.;
let meanDiff = Js.Math.pow_float(~base=y.meanDiff, ~exp=yearDiff);
let stdDevDiff = Js.Math.pow_float(~base=y.meanDiff, ~exp=yearDiff);
FloatCdf.normal(currentValue *. meanDiff, firstYearStdDev *. stdDevDiff);
};
let rec currentValue = (group: group, output) => {
let sum = (): float =>
currentValue(Fund(ANIMAL_WELFARE), output)
+. currentValue(Fund(GLOBAL_HEALTH), output)
+. currentValue(Fund(LONG_TERM_FUTURE), output)
+. currentValue(Fund(META), output);
switch (group, output) {
| (Fund(ANIMAL_WELFARE), DONATIONS) => 300000.0
| (Fund(ANIMAL_WELFARE), PAYOUTS) => 2300000.0
| (Fund(GLOBAL_HEALTH), DONATIONS) => 1000000.0
| (Fund(GLOBAL_HEALTH), PAYOUTS) => 500000.0
| (Fund(LONG_TERM_FUTURE), DONATIONS) => 600000.0
| (Fund(LONG_TERM_FUTURE), PAYOUTS) => 120000.0
| (Fund(META), DONATIONS) => 9300000.0
| (Fund(META), PAYOUTS) => 830000.0
| (All, _) => sum()
};
};
let make =
(
group: group,
dateTime: MomentRe.Moment.t,
currentDateTime: MomentRe.Moment.t,
output: output,
) => {
Prop.Value.FloatCdf(
calculateDifference(
currentValue(group, output),
dateTime,
currentDateTime,
yearlyMeanGrowthRateIfNotClosed(group),
),
);
};
};
module Interface = {
open Data;
let convertChoice = (s: string) =>
switch (s) {
| "animal" => Fund(ANIMAL_WELFARE)
| "globalHealth" => Fund(GLOBAL_HEALTH)
| "longTerm" => Fund(LONG_TERM_FUTURE)
| "meta" => Fund(META)
| _ => All
};
let convertOutput = (s: string) =>
switch (s) {
| "donations" => DONATIONS
| _ => PAYOUTS
};
let run = (p: Prop.Combo.t) => {
let get = Prop.ValueMap.get(p.inputValues);
switch (
get("Fund"),
get("Day"),
get(Prop.TypeWithMetadata.currentYear.id),
get("Output"),
) {
| (
Some(SelectSingle(fund)),
Some(DateTime(intendedYear)),
Some(DateTime(currentYear)),
Some(SelectSingle(output)),
) =>
Some(
Model.make(
convertChoice(fund),
intendedYear,
currentYear,
convertOutput(output),
),
)
| _ => None
};
};
let model: Prop.Model.t =
Prop.{
name: "EA Funds: Donations & Payouts",
description: "Calculate the payments and payouts of EA Funds based on existing data.",
version: "1.0.0",
author: "Ozzie Gooen",
inputTypes: [|
TypeWithMetadata.make(
~name="Fund",
~type_=
SelectSingle({
default: Some("total"),
options: [
{name: "Animal Welfare Fund", id: "animal"},
{name: "Global Health Fund", id: "globalHealth"},
{name: "Long Term Future Fund", id: "longTerm"},
{name: "Meta Fund", id: "longterm"},
{name: "All", id: "all"},
],
}),
(),
),
TypeWithMetadata.make(
~name="Day",
~type_=
DateTime({
default:
Some(
MomentRe.Moment.add(
~duration=MomentRe.duration(5., `years),
MomentRe.momentNow(),
),
),
min:
Some(
MomentRe.Moment.subtract(
~duration=MomentRe.duration(20., `years),
MomentRe.momentNow(),
),
),
max:
Some(
MomentRe.Moment.add(
~duration=MomentRe.duration(20., `years),
MomentRe.momentNow(),
),
),
}),
(),
),
TypeWithMetadata.currentYear,
TypeWithMetadata.make(
~name="Output",
~type_=
SelectSingle({
default: Some("Output"),
options: [
{name: "Donations", id: "donations"},
{name: "Funding", id: "funding"},
],
}),
(),
),
|],
outputTypes: [||],
run,
};
};