squiggle/src/models/EAFunds.re

301 lines
7.9 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
2020-02-10 23:10:03 +00:00
| CHANCE_OF_EXISTENCE
2020-02-10 20:37:12 +00:00
| PAYOUTS;
2020-02-10 23:10:03 +00:00
type conditionals =
| WORLD_CATASTROPHE;
2020-02-10 20:37:12 +00:00
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),
2020-04-01 18:49:59 +00:00
Some(400000.0),
Some(100000.0),
2020-02-10 20:37:12 +00:00
),
makeFundWithInfo(
"Global Health Fund",
Fund(GLOBAL_HEALTH),
2020-04-01 18:49:59 +00:00
Some(400000.0),
Some(100000.0),
2020-02-10 20:37:12 +00:00
),
makeFundWithInfo(
"Long Term Future Fund",
Fund(LONG_TERM_FUTURE),
2020-04-01 18:49:59 +00:00
Some(400000.0),
Some(100000.0),
2020-02-10 20:37:12 +00:00
),
makeFundWithInfo(
"Meta Fund",
Fund(ANIMAL_WELFARE),
2020-04-01 18:49:59 +00:00
Some(400000.0),
Some(100000.0),
2020-02-10 20:37:12 +00:00
),
makeFundWithInfo("All", All, None, None),
|];
};
module Model = {
open Data;
let currentYear = 2020.;
2020-04-01 18:49:59 +00:00
let firstYearStdDev = 400000.;
2020-02-10 20:37:12 +00:00
type yearlyNumericDiff = {
meanDiff: float,
stdDiff: float,
};
let yearlyMeanGrowthRateIfNotClosed = (group: group): yearlyNumericDiff => {
2020-04-01 18:49:59 +00:00
{meanDiff: 1.1, stdDiff: 1.2};
2020-02-10 20:37:12 +00:00
};
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);
2020-02-25 20:08:53 +00:00
let stdDevDiff = Js.Math.pow_float(~base=y.stdDiff, ~exp=yearDiff);
2020-02-16 12:27:44 +00:00
GuesstimatorDist.logNormal(
2020-02-13 12:40:04 +00:00
currentValue *. meanDiff,
firstYearStdDev *. stdDevDiff,
);
2020-02-10 20:37:12 +00:00
};
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()
2020-02-10 23:10:03 +00:00
| (_, CHANCE_OF_EXISTENCE) => 0.0
2020-02-10 20:37:12 +00:00
};
};
2020-02-17 19:45:32 +00:00
let xRisk = conditionals =>
Prop.Value.ConditionalArray.get(conditionals, "Global Existential Event");
2020-02-21 11:45:32 +00:00
// TODO: Fixe number that integral is calculated for
let getGlobalCatastropheChance = dateTime => {
2020-02-23 18:34:34 +00:00
GlobalCatastrophe.makeI(MomentRe.momentNow())
2020-04-05 06:36:14 +00:00
|> RenderTypes.DistPlusRenderer.make(~distPlusIngredients=_, ())
|> DistPlusIngredients.toDistPlus
|> E.O.bind(_, Distributions.DistPlusTime.Integral.xToY(Time(dateTime)));
2020-02-21 11:45:32 +00:00
};
2020-02-10 20:37:12 +00:00
let make =
(
group: group,
dateTime: MomentRe.Moment.t,
currentDateTime: MomentRe.Moment.t,
output: output,
2020-02-17 19:45:32 +00:00
conditionals: array(Prop.Value.conditional),
2020-02-10 20:37:12 +00:00
) => {
2020-02-17 19:45:32 +00:00
let xRisk = xRisk(conditionals);
2020-02-10 23:10:03 +00:00
switch (output) {
| DONATIONS
| PAYOUTS =>
let difference =
2020-02-10 23:10:03 +00:00
calculateDifference(
currentValue(group, output),
dateTime,
currentDateTime,
yearlyMeanGrowthRateIfNotClosed(group),
);
2020-02-18 13:23:02 +00:00
2020-02-17 19:45:32 +00:00
let str =
switch (xRisk) {
| Some({truthValue: true}) => "0"
| Some({truthValue: false}) => difference
2020-02-21 11:45:32 +00:00
| None =>
let foo =
getGlobalCatastropheChance(dateTime)
2020-04-01 18:49:59 +00:00
|> E.O.fmap(r => {
let chance = r;
let opposite = 1.0 -. r;
let reg = difference;
{j|mm(0, $reg, [$chance, $opposite])|j};
});
2020-02-21 11:45:32 +00:00
foo |> E.O.default("");
2020-02-17 19:45:32 +00:00
};
2020-02-18 13:23:02 +00:00
let distPlusIngredients =
DistPlusIngredients.make(
~guesstimatorString=str,
~domain=Complete,
2020-02-19 07:54:40 +00:00
~unit=UnspecifiedDistribution,
(),
);
Prop.Value.DistPlusIngredients(distPlusIngredients);
2020-02-19 07:54:40 +00:00
2020-02-17 19:45:32 +00:00
| CHANCE_OF_EXISTENCE =>
Prop.Value.DistPlusIngredients(
DistPlusIngredients.make(
~guesstimatorString=
GuesstimatorDist.min(
GlobalCatastrophe.guesstimatorString,
2020-02-25 20:08:53 +00:00
GuesstimatorDist.logNormal(20., 2.),
2020-02-17 19:45:32 +00:00
),
2020-02-25 20:08:53 +00:00
~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
2020-02-17 19:45:32 +00:00
~domain=RightLimited({xPoint: 100., excludingProbabilityMass: 0.3}),
(),
),
)
2020-02-10 23:10:03 +00:00
};
2020-02-10 20:37:12 +00:00
};
};
module Interface = {
open Data;
2020-02-10 21:16:17 +00:00
let fundKey = "Fund";
let dayKey = "Day";
let outputKey = "Output";
let choiceFromString = (s: string) =>
funds |> E.A.getBy(_, r => r.name == s);
let outputFromString = (s: string) =>
2020-02-10 20:37:12 +00:00
switch (s) {
| "donations" => DONATIONS
2020-02-10 23:10:03 +00:00
| "exists" => CHANCE_OF_EXISTENCE
2020-02-10 20:37:12 +00:00
| _ => PAYOUTS
};
2020-02-17 16:53:30 +00:00
let run = (p: array(option(Prop.Value.t))) => {
switch (p) {
2020-02-10 21:16:17 +00:00
| [|
2020-02-10 20:37:12 +00:00
Some(SelectSingle(fund)),
Some(DateTime(intendedYear)),
Some(DateTime(currentYear)),
Some(SelectSingle(output)),
2020-02-17 19:45:32 +00:00
Some(ConditionalArray(conditionals)),
2020-02-10 21:16:17 +00:00
|] =>
choiceFromString(fund)
|> E.O.fmap(fund =>
Model.make(
fund.group,
intendedYear,
currentYear,
outputFromString(output),
2020-02-17 19:45:32 +00:00
conditionals,
2020-02-10 21:16:17 +00:00
)
)
2020-02-10 20:37:12 +00:00
| _ => None
};
};
let model: Prop.Model.t =
Prop.{
2020-02-26 09:36:26 +00:00
id: "ea-funds",
name: "EA Funds: Donations & Payouts",
description: "Calculate the payments and payouts of CEA Funds based on existing data.",
2020-02-10 20:37:12 +00:00
version: "1.0.0",
fileName: "EAFunds.re",
2020-02-10 20:37:12 +00:00
author: "Ozzie Gooen",
inputTypes: [|
TypeWithMetadata.make(
2020-02-10 21:16:17 +00:00
~name=fundKey,
2020-02-10 20:37:12 +00:00
~type_=
SelectSingle({
2020-02-10 21:16:17 +00:00
default: Some(Array.unsafe_get(Data.funds, 0).name),
options:
Data.funds
|> E.A.fmap((r) =>
({name: r.name, id: r.name}: Prop.Type.selectOption)
)
|> Array.to_list,
2020-02-10 20:37:12 +00:00
}),
(),
),
TypeWithMetadata.make(
2020-02-10 21:16:17 +00:00
~name=dayKey,
2020-02-10 20:37:12 +00:00
~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(
2020-02-10 21:16:17 +00:00
~name=outputKey,
2020-02-10 20:37:12 +00:00
~type_=
SelectSingle({
default: Some("Output"),
options: [
2020-02-17 19:45:32 +00:00
{name: "Donations", id: "donations"},
{name: "Funding", id: "funding"},
{name: "Closing", id: "exists"},
2020-02-10 20:37:12 +00:00
],
}),
(),
),
2020-02-13 21:24:47 +00:00
TypeWithMetadata.make(
2020-02-13 22:04:13 +00:00
~name="Conditionals",
~id="conditionals",
2020-02-13 21:24:47 +00:00
~type_=
Conditionals(
2020-02-13 22:04:13 +00:00
Prop.Type.makeConditionals(
[||],
[|"Global Existential Event"|],
),
2020-02-13 21:24:47 +00:00
),
(),
),
2020-02-10 20:37:12 +00:00
|],
outputTypes: [||],
run,
};
2020-02-13 21:24:47 +00:00
};