/// <summary> /// Step one year /// </summary> /// <param name="state"></param> /// <param name="log"></param> static bool Step(State state, DDataTable log) { // advance time state.CurrentYear++; // record values log.StartRow(); log.AddData(state.CurrentYear, Col.Make(ColType.Info, "Year")); var inflation = StateUtils.GetRate(state.Rates, State.InflationName, (int)state.CurrentYear); log.AddData(inflation, Col.Make(ColType.Info, "InflationModel")); log.AddData(StateUtils.TotalRate((int)state.StartYear, (int)state.CurrentYear, StateUtils.GetRateItem(state.Rates, State.InflationName)), AccumulatedInflationColumnName); log.AddData(StateUtils.GetRate(state.Rates, State.StockReturnsName, (int)state.CurrentYear), Col.Make(ColType.Info, "Stock returns")); log.AddData(StateUtils.TotalRate((int)state.StartYear, (int)state.CurrentYear, StateUtils.GetRateItem(state.Rates, State.StockReturnsName)), Col.Make(ColType.Info, "Accum stock returns")); foreach (var actor in state.Actors) { actor.Age++; if (!actor.Step(log, inflation, state)) { return(false); // step failed - bankrupt } } return(true); }
public double ComputeTax(DDataTable log, double compoundInflation) { var fed = Federal.Compute(log, compoundInflation); State.AdjustedGrossIncome = Federal.AdjustedGrossIncome; State.Exemptions = Federal.Exemptions; var state = State.Compute(log, compoundInflation); return(fed + state); }
/// <summary> /// Run the simulation on the state /// </summary> /// <param name="state"></param> /// <param name="randSeed"></param> /// <param name="log"></param> public static void Simulate(State state, ulong randSeed, DDataTable log) { InitState(state, randSeed); for (var i = 0; i < state.NumYears; ++i) { if (!Step(state, log)) { return; } } }
public double Compute(DDataTable log, double compoundInflation) { var totalDeductions = HomeownerPropertyTax + TaxableSocialSecurityBenefits; var totalExemptions = compoundInflation * Exemptions * 1000; totalExemptions += compoundInflation * PeopleOver65 * 1000; if (AdjustedGrossIncome < 40000) { totalExemptions += compoundInflation * PeopleOver65 * 500; } var indianaGrossIncome = AdjustedGrossIncome - totalDeductions - totalExemptions; var stateTax = 0.0323 * indianaGrossIncome; var countyTax = 0.013825 * indianaGrossIncome; return(stateTax + countyTax); }
/// <summary> /// Compute federal tax /// </summary> /// <param name="log"></param> /// <param name="compoundInflation"></param> /// <returns></returns> public double Compute(DDataTable log, double compoundInflation) { // see http://taxhow.net/articles/1040-step-by-step-guide // todo - Alternative Minimum Tax var totalIncome = 0.0; totalIncome += Wages; totalIncome += TaxableInterest; totalIncome += OrdinaryDividends; totalIncome += BusinessIncomeOrLoss; totalIncome += CapitalGainOrLoss; totalIncome += IraDistributionsTaxableAmount; totalIncome += PensionAndAnnuitiesTaxableAmount; totalIncome += SocialSecurityTaxableAmount; totalIncome += OtherIncomeTaxableAmount; AdjustedGrossIncome = totalIncome - IraDeduction; // todo - other things here // todo - implement itemized deductions // todo - these are 2018+ sizes var standardDeduction = compoundInflation * 12000; if (FilingStatus == FilingStatus.MarriedJointly) { standardDeduction = compoundInflation * 24000; } var exemptionDeduction = 0.0; // personal exemption removed in 2018 //if (adjustedGrossIncome < compoundInflation * 155650) // todo - also tapers off // exemptionDeduction = Exemptions * compoundInflation * 4150; var taxableIncome = AdjustedGrossIncome - standardDeduction - exemptionDeduction; var totalTax = ComputeTax(taxableIncome, taxBackets2018, compoundInflation); // todo - social security tax? take before agi? return(totalTax); }
/// <summary> /// return logger that has data for monte carlo sim /// todo - count, parallel /// </summary> /// <param name="state"></param> /// <param name="count"></param> /// <returns></returns> public static async Task <Tuple <GDataTable, double[]> > RunSimulations(State state, int count, ulong randomSeed, double [] percentiles) { var logs = new ConcurrentQueue <DDataTable>(); await Task.Run(() => { var rand1 = new LocalRandom(true, randomSeed); var seeds = new ulong[count]; for (var i = 0; i < count; ++i) { seeds[i] = rand1.Next64(); } Parallel.For(0, count, n => { var log = new DDataTable(); var tempState = DeepClone(state); Simulation.Simulate(tempState, seeds[n], log); logs.Enqueue(log); }); }); var finalLog = new GDataTable(); if (count == 1) { // create log of proper type var log = logs.First(); foreach (var row in Enumerable.Range(0, log.RowCount)) { finalLog.StartRow(); foreach (var col in Enumerable.Range(0, log.ColCount)) { finalLog.AddData(new double[] { log[row, col] }, log.ColumnNames[col]); } } return(new Tuple <GDataTable, double[]>(finalLog, new double[] { 0.50 })); } // sort by sum of total worths in item var sortedLogs = new List <Tuple <DDataTable, double> >(); foreach (var log in logs) { var maxCol = log.ColumnNames.Count; var lastRow = log.RowCount - 1; var value = 0.0; for (var i = 0; i < maxCol; ++i) { if (log.ColumnNames[i].ToString().Contains(Actor.FinalValueText)) { value += log[lastRow, i]; } } sortedLogs.Add(new Tuple <DDataTable, double>(log, value)); } sortedLogs.Sort((a, b) => a.Item2.CompareTo(b.Item2)); var rowMax = sortedLogs.Max(r => r.Item1.RowCount); var columnNames = sortedLogs[0].Item1.ColumnNames; foreach (var row in Enumerable.Range(0, rowMax + 1)) { finalLog.StartRow(); foreach (var name in columnNames) { var value = new List <double>(); foreach (var entry in percentiles) { var log = sortedLogs[(int)(sortedLogs.Count * entry)].Item1; var column = log.GetColumn(name); if (column.Count > row) { value.Add(column[row]); } } finalLog.AddData(value.ToArray(), name); } } return(new Tuple <GDataTable, double[]>(finalLog, percentiles)); }