Last active
May 22, 2018 20:10
-
-
Save patefacio/d861650e7297b4d27c6e0c591a43cb12 to your computer and use it in GitHub Desktop.
Perf Issue HTML only
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bash-3.2$ time curl -H "Accept: text/html" http://localhost:8002/forecast/214/1116543?use_item_assumptions=true > /tmp/goo.html | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 321k 100 321k 0 0 168k 0 0:00:01 0:00:01 --:--:-- 168k | |
real 0m1.921s | |
user 0m0.008s | |
sys 0m0.006s | |
bash-3.2$ time curl http://localhost:8002/forecast/214/1116543?use_item_assumptions=true > /tmp/goo.json | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 657k 100 657k 0 0 32.6M 0 --:--:-- --:--:-- --:--:-- 33.8M | |
real 0m0.032s | |
user 0m0.008s | |
sys 0m0.007s |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bash-3.2$ time curl -H "Accept: text/html" -skw "\ntime_connect: %{time_connect}s\ntime_namelookup: %{time_namelookup}s\ntime_pretransfer: %{time_pretransfer}\ntime_starttransfer: %{time_starttransfer}s\ntime_redirect: %{time_redirect}s\ntime_total: %{time_total}s\n\n" -Lo /tmp/goo.html http://localhost:8002/forecast/214/1116543?use_item_assumptions=true | |
time_connect: 0.004878s | |
time_namelookup: 0.004677s | |
time_pretransfer: 0.004906 | |
time_starttransfer: 2.004142s | |
time_redirect: 0.000000s | |
time_total: 2.004880s | |
real 0m2.017s | |
user 0m0.007s | |
sys 0m0.006s | |
bash-3.2$ time curl -skw "\ntime_connect: %{time_connect}s\ntime_namelookup: %{time_namelookup}s\ntime_pretransfer: %{time_pretransfer}\ntime_starttransfer: %{time_starttransfer}s\ntime_redirect: %{time_redirect}s\ntime_total: %{time_total}s\n\n" -Lo /tmp/goo.json http://localhost:8002/forecast/214/1116543?use_item_assumptions=true | |
time_connect: 0.004826s | |
time_namelookup: 0.004578s | |
time_pretransfer: 0.004871 | |
time_starttransfer: 0.020730s | |
time_redirect: 0.000000s | |
time_total: 0.022098s | |
real 0m0.035s | |
user 0m0.008s | |
sys 0m0.007s | |
bash-3.2$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Collection of tera filters | |
// --- module imports --- | |
extern crate separator; | |
// --- module use statements --- | |
use rocket_contrib::tera::{self, to_value, Value}; | |
use rocket_contrib::{Engines, Template}; | |
use self::separator::Separatable; | |
use std::collections::HashMap; | |
// --- module function definitions --- | |
/// Register all custom tera filters | |
/// | |
/// * `engines` - Engines, to add some tera filters | |
/// | |
pub fn register_filters(engines: &mut Engines) -> () { | |
info!("Registering tera filters"); | |
engines.tera.register_filter("as_number", as_number); | |
engines.tera.register_filter("as_money", as_money); | |
engines.tera.register_filter("as_percent", as_percent); | |
engines.tera.register_filter( | |
"sheltered_qualified_dividends", | |
sheltered_qualified_dividends, | |
); | |
} | |
/// Formats an integer with commas | |
/// | |
/// * `value` - Value being transformed | |
/// * `args` - Arguments to filter | |
/// * _return_ - Transformed value | |
/// | |
fn as_number(value: Value, _args: HashMap<String, Value>) -> tera::Result<Value> { | |
let result: Value; | |
// custom <fn as_number> | |
use serde_json::from_value; | |
let value: i64 = match from_value::<i64>(value.clone()) { | |
Ok(s) => s, | |
Err(_) => { | |
return Err(format!( | |
"Filter `{}` was called on an incorrect value: got `{}` but expected a {}", | |
"as_number", | |
value, | |
stringify!(i64) | |
).into()); | |
} | |
}; | |
result = to_value(if value > 0 { | |
format!("{}", value.separated_string()) | |
} else if value < 0 { | |
format!("({})", (-value).separated_string()) | |
} else { | |
"_".to_string() | |
}).unwrap(); | |
// end <fn as_number> | |
Ok(result) | |
} | |
/// Formats floating point input as money with consisting rounding, commas, etc | |
/// | |
/// * `value` - Value being transformed | |
/// * `args` - Arguments to filter | |
/// * _return_ - Transformed value | |
/// | |
fn as_money(value: Value, _args: HashMap<String, Value>) -> tera::Result<Value> { | |
let result: Value; | |
// custom <fn as_money> | |
use serde_json::from_value; | |
let value: f64 = match from_value::<f64>(value.clone()) { | |
Ok(s) => s, | |
Err(_) => { | |
return Err(format!( | |
"Filter `{}` was called on an incorrect value: got `{}` but expected a {}", | |
"as_money", | |
value, | |
stringify!(f64) | |
).into()); | |
} | |
}; | |
result = to_value(if value > 0.0 { | |
format!("${}", value.separated_string()) | |
} else if value < 0.0 { | |
format!("$({})", (-value).separated_string()) | |
} else { | |
"_".to_string() | |
}).unwrap(); | |
// end <fn as_money> | |
Ok(result) | |
} | |
/// Formats floating point input as a percentage | |
/// | |
/// * `value` - Value being transformed | |
/// * `args` - Arguments to filter | |
/// * _return_ - Transformed value | |
/// | |
fn as_percent(value: Value, _args: HashMap<String, Value>) -> tera::Result<Value> { | |
let result: Value; | |
// custom <fn as_percent> | |
use serde_json::from_value; | |
let value: f64 = match from_value::<f64>(value.clone()) { | |
Ok(s) => s, | |
Err(_) => { | |
return Err(format!( | |
"Filter `{}` was called on an incorrect value: got `{}` but expected a {}", | |
"as_money", | |
value, | |
stringify!(f64) | |
).into()); | |
} | |
}; | |
result = to_value(format!("{:.2}%", value*100.0)).unwrap(); | |
// end <fn as_percent> | |
Ok(result) | |
} | |
/// Returns list of sheltered qualified dividends from `Worksheet` if any, or empty list if none | |
/// | |
/// * `value` - Value being transformed | |
/// * `args` - Arguments to filter | |
/// * _return_ - Transformed value | |
/// | |
fn sheltered_qualified_dividends( | |
value: Value, _args: HashMap<String, Value> | |
) -> tera::Result<Value> { | |
let result: Value; | |
// custom <fn sheltered_qualified_dividends> | |
result = to_value("TODO!!").unwrap(); | |
// end <fn sheltered_qualified_dividends> | |
Ok(result) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% import "worksheets" as worksheets %} | |
{% import "balance_sheet_proof" as bsp %} | |
{% import "forecast_config" as forecast_config %} | |
{% import "core" as core %} | |
{% import "end_balance_streams" as end_balance_streams %} | |
{% import "assumption_details" as assumption_details %} | |
{% set start_year = year_range.start %} | |
{% set end_year = year_range.end %} | |
{% set num_years = end_year - start_year %} | |
{% set forecast_config = forecast_details.forecast_config %} | |
{% set bsps = forecast_details.balance_sheet_proofs %} | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>"{{ forecast_details.dossier_name }}" Forecast</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> | |
</head> | |
<body style="background-color: rgb(255,255,204,0.2);"> | |
<div class="card-body" style="width: 60rem;"> | |
<h5 class="card-title"> | |
{% if forecast_id == 0 %} | |
<i>Geometric Mean Forecast</i> | |
{% else %} | |
<i>Random Forecast (id={{forecast_id | as_number}})</i> | |
{% endif %} | |
</h5> | |
<div class="container"> | |
<div class="row"> | |
<div class="col-sm"> | |
<div class="container"> | |
<div class="card"> | |
<div class="card-body"> | |
<h4 class="card-title">Forecast Details</h4> | |
<table class="user-table table-sm table-striped"> | |
{% if forecast_details %} | |
<tr> | |
<td nowrap><strong>Dossier<strong></td> | |
<td nowrap><em>{{ forecast_details.dossier_name }} ({{dossier_id | as_number}})</em></td> | |
</tr> | |
<tr> | |
<td><strong>Duration:</strong></td> | |
<td>{{ forecast_details.forecast_millis | as_number }} ms</td> | |
</tr> | |
{% endif %} | |
{{ forecast_config::configured_range(forecast_config=forecast_config) }} | |
{{ forecast_config::year_range(range=year_range, label="Evaluated Range") }} | |
<td nowrap>Forecast Tax Override</td> | |
<td nowrap>{{ forecast_config.forecast_tax_treatment }}</td> | |
</tr> | |
<tr> | |
<td nowrap>Primary User</td> | |
<td nowrap>{{ forecast_config.primary_user }}</td> | |
</tr> | |
<tr> | |
<td nowrap>Growth Outlook</td> | |
<td nowrap>{{ forecast_config.growth_outlook }}</td> | |
</tr> | |
<tr> | |
<td nowrap>Inflation</td> | |
<td>{{ core::rate_curve_pct(rc=forecast_config.inflation) }}</td> | |
</tr> | |
<tr> | |
<td nowrap>Cost of Capital</td> | |
<td>{{ core::rate_curve_pct(rc=forecast_config.cost_of_capital) }}</td> | |
</tr> | |
</table> | |
</div> | |
</div> | |
</div> | |
</div> | |
{% if forecast_details %} | |
<div class="col-sm"> | |
<div class="container"> | |
{% set user_markers = forecast_details.year_markers.user_markers %} | |
{% if user_markers %} | |
<div class="card"> | |
<div class="card-body"> | |
<h4 class="card-title">Person Events</h4> | |
<table class="user-year-markers-table table-sm table-striped"> | |
<tr> | |
<th>Person</th> | |
<th nowrap>Event</th> | |
<th nowrap>Age/Year</th> | |
</tr> | |
{% for uym in user_markers %} | |
<tr> | |
<th nowrap>{{uym.user}}</th> | |
<th nowrap> | |
{{ uym.user_year_marker_type }} | |
</th> | |
<th nowrap>{{uym.year - uym.birth_year}}/{{uym.year}}</th> | |
</tr> | |
{% endfor %} | |
</table> | |
</div> | |
</div> | |
{% endif %} | |
</div> | |
</div> | |
{% endif %} | |
</div> | |
</div> | |
{% set end_balance_streams = forecast_details.end_balance_streams %} | |
{% set worksheets = forecast_details.worksheets %} | |
{% set inflation = forecast_details.inflation * 100.0 %} | |
<table class="end-balance-table table-sm table-striped"> | |
<tr><td class="table-success" colspan="5" style="text-align:center; border-bottom:2px solid blue; border-top: 2px solid blue;"><h4>Balances Sheet Items</h4></td></tr> | |
<theader> | |
<tr> | |
<th>Item</th> | |
<th nowrap>Growth Item</th> | |
<th >Assumption Source</th> | |
<th >Growth Assumption</th> | |
<th style="text-align:right">Realized Log-Ret</th> | |
<th >PV Final Year @ {{inflation | round(precision=2)}}%</th> | |
<th style="text-align:right">Initial</th> | |
{{ worksheets::year_headers(worksheets=worksheets)}} | |
</tr> | |
</theader> | |
<tbody> | |
{% if forecast_details.item_identifiers.worths %} | |
<tr><td class="table-warning" colspan="5" style="text-align:center; border-bottom:2px solid blue; border-top: 2px solid blue;"><em>Non Financial Assets</em></td></tr> | |
{% endif %} | |
{% for ebs in end_balance_streams %} | |
{% if forecast_details.item_identifiers.worths | length == loop.index - 1 %} | |
<tr><td class="table-warning" colspan="5" style="text-align:center; border-bottom:2px solid blue; border-top: 2px solid blue;"><em>Financial Assets</em></td></tr> | |
{% endif %} | |
{% set ad = ebs.assumption_details %} | |
<tr> | |
<td nowrap>{{ad.id}}</td> | |
{{ assumption_details::assumption_details(assumption_details=ad) }} | |
{% if ad.growth_assumption_details %} | |
{{ assumption_details::resolved_growth_source(growth_assumption_details=ad.growth_assumption_details) }} | |
{{ assumption_details::normal(normal_spec=ad.growth_assumption_details.growth.growth_assumption.normal_spec) }} | |
{% endif %} | |
{% set log_ret = ebs.log_returns * 100.0 / num_years %} | |
<td nowrap style="text-align:right">{{ log_ret | round(precision=3) }} %</td> | |
<td style="text-align:right; border-right: 2px solid blue;">{{ebs.pv_end_balance | round(precision=0) | as_money }}</td> | |
<td style="text-align:right"> {{ ebs.initial_balance | round(precision=0) | as_money }} </td> | |
{{ end_balance_streams::end_balances(end_balance_streams=ebs) }} | |
</tr> | |
{% endfor %} | |
<tr class="table-info" ><td colspan="5" style="border-bottom: 2px solid green;"></td></tr> | |
{{ worksheets::label_row(label="Basic Allocation") }} | |
{{ worksheets::end_balance_detail_inset_row(label="Stock", table_row=worksheets::stock_allocation(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Bond", table_row=worksheets::bond_allocation(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Cash", table_row=worksheets::cash_allocation(worksheets=worksheets)) }} | |
{# {{ worksheets::end_balance_detail_inset_row(label="Other", table_row=worksheets::other_allocation(worksheets=worksheets)) }} #} | |
{{ worksheets::net_worth_row(pv_end_value=forecast_details.pv_end_net_value, worksheets=worksheets) }} | |
<tr><td class="table-success" colspan="5" style="text-align:center; border-bottom:2px solid blue; border-top: 2px solid blue;"><h4>Annual Details</h4></td></tr> | |
{% if forecast_details.total_sheltered_distributions != 0.0 %} | |
{{ worksheets::label_row(label="Sheltered Distributions") }} | |
{{ worksheets::end_balance_detail_inset_row(label="Sheltered Qualified Divs", table_row=worksheets::sheltered_qualified_dividends(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Sheltered Unqualified Divs", table_row=worksheets::sheltered_unqualified_dividends(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Sheltered Cap Gain Dist", table_row=worksheets::sheltered_capital_gain_distributions(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Sheltered Interest", table_row=worksheets::sheltered_interest(worksheets=worksheets)) }} | |
{% endif %} | |
{% if forecast_details.total_taxable_distributions != 0.0 %} | |
{{ worksheets::label_row(label="Non-Sheltered Distributions") }} | |
{{ worksheets::end_balance_detail_inset_row(label="Qualified Divs", table_row=worksheets::qualified_dividends(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Unqualified Divs", table_row=worksheets::unqualified_dividends(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Cap Gain Dist", table_row=worksheets::capital_gain_distributions(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Interest", table_row=worksheets::interest(worksheets=worksheets)) }} | |
{% endif %} | |
{{ worksheets::label_row(label="Taxable Distributions By Treatment") }} | |
{{ worksheets::end_balance_detail_inset_row(label="Reinvested", table_row=worksheets::reinvested(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Disbursed", table_row=worksheets::disbursed(worksheets=worksheets)) }} | |
{{ worksheets::label_row(label="Capital Gains/Losses") }} | |
{{ worksheets::end_balance_detail_row(label="Long Term Cap Gains/(Loss)", table_row=worksheets::long_term_capital_gains(worksheets=worksheets)) }} | |
{% if forecast_details.total_penalties != 0.0 %} | |
{{ worksheets::label_row(label="Loss Carry Forward Details") }} | |
{{ worksheets::end_balance_detail_row(label="Prior Losses Available", table_row=worksheets::prior_losses_available(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Losses Offsetting Gains", table_row=worksheets::losses_offsetting_gains(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Losses Offsetting Ord Inc", table_row=worksheets::losses_offsetting_ordinary_income(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Remaining Losses", table_row=worksheets::remaining_losses(worksheets=worksheets)) }} | |
{% endif %} | |
{{ worksheets::end_balance_summary_row(label="Total Income", table_row=worksheets::total_income(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Earned Income", table_row=worksheets::earned_income(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Passive Income", table_row=worksheets::passive_income(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Portfolio Income", table_row=worksheets::portfolio_income(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Ordinary Income", table_row=worksheets::ordinary_income(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Required Min Dist", table_row=worksheets::rmd(worksheets=worksheets)) }} | |
{% if forecast_details.total_retirement_investments != 0.0 %} | |
{{ worksheets::end_balance_detail_inset_row(label="Retirement Deductions", table_row=worksheets::retirement_deductions(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Retirement Investments", table_row=worksheets::retirement_contributions(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Employer Match", table_row=worksheets::employer_match(worksheets=worksheets)) }} | |
{% endif %} | |
{% if forecast_details.total_penalties != 0.0 %} | |
{{ worksheets::label_row(label="Penalties") }} | |
{{ worksheets::end_balance_detail_inset_row(label="College 529 Penalties", table_row=worksheets::college_penalties(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="HSA Penalties", table_row=worksheets::health_care_penalty(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Early Withdrawal Penalties", table_row=worksheets::early_withdrawal_penalty(worksheets=worksheets)) }} | |
{% endif %} | |
{{ worksheets::end_balance_summary_row(label="Adjusted Gross Income", table_row=worksheets::agi(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Tax Basis", table_row=worksheets::tax_basis(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Standard Deduction", table_row=worksheets::standard_deduction(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Marginal Rate", table_row=worksheets::marginal_tax_rates(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Effective Rate", table_row=worksheets::effective_tax_rates(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_row(label="Total Tax Bill", table_row=worksheets::total_tax_bill(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Ordinary Tax Bill", table_row=worksheets::tax_bill(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Soc. Sec. Tax", table_row=worksheets::social_security_tax(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Medicare Tax", table_row=worksheets::medicare_tax(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Long Term Cap Gain Tax", table_row=worksheets::long_term_capital_gains_tax(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="On LTCG", table_row=worksheets::long_term_capital_gains(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="With LTCG Hurdle", table_row=worksheets::long_term_capital_gains_hurdle(worksheets=worksheets)) }} | |
{# | |
<tr><td class="table-primary" colspan="5" style="text-align:center; border-bottom:2px solid blue; border-top: 2px solid blue;"><h5>Flow Summary</h5></td></tr> | |
{{ worksheets::end_balance_summary_row(label="Net Flows", table_row=worksheets::net_flows(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Total Inflows", table_row=worksheets::inflows(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Total Outflows", table_row=worksheets::outflows(worksheets=worksheets)) }} | |
#} | |
{{ worksheets::end_balance_summary_row(label="Remaining Shortfall", table_row=worksheets::remaining_shortfalls(worksheets=worksheets)) }} | |
{{ worksheets::label_row(label="Balance Breakdown") }} | |
{{ worksheets::end_balance_detail_row(label="Start Balance", table_row=worksheets::summary_start_balances(worksheets=worksheets)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Total Increases", table_row=bsp::total_up(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Worth Growth", table_row=bsp::worth_growth(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Holding Growth", table_row=bsp::holding_growth(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Modeled Inflows", table_row=bsp::modeled_inflows(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Employer Match", table_row=bsp::employer_match(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_inset_row(label="Total Decreases", table_row=bsp::total_down(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Modeled Outflows", table_row=bsp::modeled_outflows(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Tax Bill", table_row=bsp::tax_bill(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_double_inset_row(label="Penalties", table_row=bsp::penalties(bsps=bsps)) }} | |
{{ worksheets::end_balance_detail_row(label="Proof End Balance", table_row=bsp::proof_end_balance(bsps=bsps)) }} | |
{% set cash_flow_streams = forecast_details.cash_flow_streams %} | |
{% if cash_flow_streams %} | |
<tr><td class="table-success" colspan="5" style="text-align:center; border-bottom:2px solid blue; border-top: 2px solid blue;"><h4>Modeled Cash Flows</h4></td></tr> | |
<tr> | |
<th>Flow</th> | |
<th nowrap>Growth Item</th> | |
<th >Assumption Source</th> | |
<th >Growth Assumption</th> | |
<th style="text-align:right">Realized Log-Ret</th> | |
<th >PV Sum @ {{inflation | round(precision=2)}}%</th> | |
<th style="text-align:right">Initial</th> | |
{{ worksheets::year_headers(worksheets=worksheets)}} | |
</tr> | |
{% for cfs in cash_flow_streams %} | |
{% set ad = cfs.assumption_details %} | |
<tr> | |
<td nowrap>{{ad.id}}</td> | |
{{ assumption_details::assumption_details(assumption_details=ad)}} | |
{% if ad.growth_assumption_details %} | |
{% if ad.growth_assumption_details.resolved_source == "DossierPinned" %} | |
<td nowrap>📌</td> | |
{% elif ad.growth_assumption_details.resolved_source == "DossierNormalSpec" %} | |
<td nowrap>📁</td> | |
{% else %} | |
<td nowrap>{{ad.growth_assumption_details.growth_source}}</td> | |
{% endif %} | |
{{ assumption_details::normal(normal_spec=ad.growth_assumption_details.growth.growth_assumption.normal_spec)}} | |
{% else %} | |
<td style="text-align:center">Fixed</td> | |
<td style="text-align:center">__</td> | |
<td style="text-align:center">__</td> | |
{% endif %} | |
{% if cfs.log_returns %} | |
<td nowrap style="text-align:right">{{ cfs.log_returns * 100.0 | round(precision=3)}} %</td> | |
{% else %} | |
<td nowrap style="text-align:right">_</td> | |
{% endif %} | |
<td nowrap style="text-align:right; border-right: 2px solid blue;">{{cfs.cumulative_pv | round(precision=0) | as_money }}</td> | |
<td nowrap style="text-align:right;"> | |
{% if cfs.initial_value %} | |
{% if cfs.flow_direction == "InFlow" %} | |
{% set initial_value = cfs.initial_value.value %} | |
{% set arrow = "↑" %} | |
{% else %} | |
{% set initial_value = 0.0 - cfs.initial_value.value %} | |
{% set arrow = "↓" %} | |
{% endif %} | |
{{ initial_value | round(precision=0) | as_money }}:{{arrow}} | |
{% else %} | |
_ | |
{% endif %} | |
</td> | |
{% for dv in cfs.values %} | |
<td style="text-align:right">{{dv | round(precision=0) | as_money}}</td> | |
{% endfor %} | |
</tr> | |
{% endfor %} | |
{% endif %} | |
</tbody> | |
</table> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Get a forecast for a dossier using the standard `include_forecast_details` option. | |
/// | |
/// This is a simple get version, without configuration options, of the `post_forecast` route. | |
/// | |
/// * `dossier_id` - Id of `Dossier` to forecast | |
/// * `forecast_id` - Id of `Forecast` - 0 indicating _Geometric Mean Forecast_, otherwise a _Random Forecast_ | |
/// * `get_forecast_query_parms` - Additional query parameters | |
/// * `data_layer` - Access to the `DataLayer` provided by `plus_persist` | |
/// * _return_ - The http response to request as html `Option<Template>` | |
/// | |
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] | |
#[get("/forecast/<dossier_id>/<forecast_id>?<get_forecast_query_parms>", rank = 1)] | |
fn get_forecast_html( | |
dossier_id: i32, forecast_id: u32, get_forecast_query_parms: GetForecastQueryParms, | |
data_layer: DataLayer, | |
) -> Option<Template> { | |
use stopwatch::Stopwatch; | |
let sw = Stopwatch::start_new(); | |
let result = match get_forecast( | |
dossier_id, | |
forecast_id, | |
get_forecast_query_parms, | |
data_layer, | |
) { | |
Ok(forecast) => { | |
Some(Template::render("forecast", &forecast)) | |
} | |
Err(err) => { | |
warn!("Unable to handle html request {}", err); | |
None | |
} | |
}; | |
println!("Tera Timings {} ms", sw.elapsed_ms()); | |
result | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Get a forecast for a dossier using the standard `include_forecast_details` option. | |
/// | |
/// This is a simple get version, without configuration options, of the `post_forecast` route. | |
/// | |
/// * `dossier_id` - Id of `Dossier` to forecast | |
/// * `forecast_id` - Id of `Forecast` - 0 indicating _Geometric Mean Forecast_, otherwise a _Random Forecast_ | |
/// * `get_forecast_query_parms` - Additional query parameters | |
/// * `data_layer` - Access to the `DataLayer` provided by `plus_persist` | |
/// * _return_ - The http response to request as json `Json<GetForecastReply>` | |
/// | |
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] | |
#[get("/forecast/<dossier_id>/<forecast_id>?<get_forecast_query_parms>", | |
format = "application/json", rank = 0)] | |
fn get_forecast_json( | |
dossier_id: i32, forecast_id: u32, get_forecast_query_parms: GetForecastQueryParms, | |
data_layer: DataLayer, | |
) -> Json<GetForecastReply> { | |
let mut _rest_timing_guard = ForecastTimingGuard::new( | |
"TODO".into(), | |
RestTimingType::GetTiming, | |
RestObjectType::Forecast, | |
); | |
match get_forecast( | |
dossier_id, | |
forecast_id, | |
get_forecast_query_parms, | |
data_layer, | |
) { | |
Ok(forecast) => { | |
// custom <get_forecast_json_timing> | |
if let Some(ref forecast_details) = forecast.forecast_details { | |
_rest_timing_guard | |
.forecast_timing_entry | |
.forecast_scale_details = | |
forecast_details.get_forecast_scale_details(); | |
} | |
// end <get_forecast_json_timing> | |
Json(GetForecastReply { | |
forecast: Some(forecast), | |
error_details: None, | |
}) | |
} | |
Err(err) => Json(GetForecastReply { | |
forecast: None, | |
error_details: Some(ErrorDetails { | |
error_message: format!("{}", err), | |
}), | |
}), | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// A forecast of a dossier | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct Forecast { | |
/// Database id of the dossier | |
#[serde(skip_serializing_if = "is_default")] | |
pub dossier_id: Option<i32>, | |
/// Identifier for this forecast. | |
/// | |
/// The `forecast_id` is used to seed the random generator, to provide | |
/// reproducible forecasts. | |
/// | |
pub forecast_id: u32, | |
/// Range for the forecast - may differ from input config due to bounds check | |
pub year_range: YearRange, | |
/// Net worth at end of forecast | |
pub end_net_worth: f64, | |
/// Present value of net worth at end of forecast | |
pub pv_end_net_worth: f64, | |
/// Mean of _annual_ difference between all _incomes_ and _expenses_ | |
pub mean_cash_flow_delta: f64, | |
/// Details of the forecast | |
#[serde(skip_serializing_if = "is_default")] | |
pub forecast_details: Option<Box<ForecastDetails>>, | |
} | |
/// Additional information provided when detailed results from forecast desired | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct ForecastDetails { | |
/// Name of the `Dossier` | |
pub dossier_name: String, | |
/// Config used to generate forecast - only set if `include_forecast_details` is true | |
pub forecast_config: ForecastConfig, | |
/// Identifiers for items in `Dossier` | |
pub item_identifiers: ItemIdentifiers, | |
/// User specified and inferred funding links | |
pub funding_links: MapOfStrToArrayOfStr, | |
/// Number of years in forecast | |
pub num_years: u32, | |
/// What was used to calculate taxes | |
pub forecast_tax_determinants: ForecastTaxDeterminants, | |
/// List of important years of the forecast | |
pub year_markers: YearMarkers, | |
/// List of worksheets | |
pub worksheets: Vec<Worksheet>, | |
/// Cash flow streams, returned if `include_cash_streams` requested | |
pub cash_flow_streams: Vec<CashFlowStream>, | |
/// *End Balances* of `Worth` and `Holdings`, returned if `include_balance_streams` requested | |
pub end_balance_streams: Vec<EndBalanceStream>, | |
/// User specified number for inflation rate to discount future values | |
pub inflation: f64, | |
/// Present value (discounted using `ForecastConfig::inflation`) of final net worth - for perspective | |
pub pv_end_net_value: f64, | |
/// Number of millis required to perform forecast | |
pub forecast_millis: i64, | |
/// Second accounting of end balance | |
pub balance_sheet_proofs: Vec<BalanceSheetProof>, | |
/// Sum of all penalties across all years in current dollars | |
pub total_penalties: f64, | |
/// Sum of all sheltered distributions across all years in current dollars | |
pub total_sheltered_distributions: f64, | |
/// Sum of all taxable distributions across all years in current dollars | |
pub total_taxable_distributions: f64, | |
/// Sum of all losses across all years in current dollars | |
pub total_losses: f64, | |
/// Sum of all retirement investments across all years in current dollars | |
pub total_retirement_investments: f64, | |
} | |
/// Object containing details of _EOY_ processing | |
#[derive(Clone, Default, Deserialize, PartialEq, Serialize)] | |
pub struct Worksheet { | |
/// Year for calculations | |
pub year: Year, | |
/// Entry for the inflation curve | |
pub inflation_rate_entry: CurveRateEntry, | |
/// Entry for the cost of capital curve | |
pub cost_of_capital_rate_entry: CurveRateEntry, | |
/// Age of primary owner | |
#[serde(skip_serializing_if = "is_default")] | |
pub primary_owner_age: Option<Year>, | |
/// Netting in/out flows. | |
pub netting: Netting, | |
/// Tax statement for the year | |
pub fed_tax_statement: FedTaxStatement, | |
/// Tax bill for prior year | |
pub tax_bill: f64, | |
/// Annual _net flows_, _obligations_ if cash flows are negative, _investment_ if positive. | |
/// | |
/// This is the sum of `inflows` and `outflows` plus `disbursed` less the `tax_bill`. | |
/// | |
pub net_flows: f64, | |
/// Any remaining shortfall after what can be sold has been sold | |
pub remaining_shortfall: f64, | |
/// Summary of draw-down, investment over the period | |
pub liquidation_summary: LiquidationSummary, | |
/// The taxable positions for each holding | |
pub taxable_positions: Vec<TaxablePosition>, | |
/// Penalties occurring in the year | |
pub penalties: Penalties, | |
/// Current allocation across types | |
pub basic_allocation: BasicAllocation, | |
/// Target allocation | |
#[serde(skip_serializing_if = "is_default")] | |
pub target_allocation: Option<BasicAllocation>, | |
} | |
/// A single entry in a position, representing a purchase at specific price | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct TaxLot { | |
/// Amount purchased/sold in lot | |
quantity: f64, | |
/// Price of one unit for lot | |
price: f64, | |
/// When lot was created (year of purchase/sale) | |
year: Year, | |
} | |
/// Tracks lotting associated with a `Holding` position | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct TaxablePosition { | |
/// Position sum of all lots | |
total_position: f64, | |
/// Total cost for all lots in position | |
total_cost_basis: f64, | |
/// List of tax lots. | |
/// | |
/// This is the history of the position and will be tracked iff | |
/// `TaxablePosition` is created with `from_first_lot_with_history` | |
/// | |
#[serde(skip_serializing_if = "is_default")] | |
tax_lots: Option<Vec<TaxLot>>, | |
/// Record of most recent mark price | |
mark_price: f64, | |
} | |
/// Basic allocation among three categories (stock, bond, cash) | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct BasicAllocation { | |
/// Allocation to stocks | |
stock: f64, | |
/// Allocation to bonds | |
bond: f64, | |
/// Allocation to cash | |
cash: f64, | |
/// Allocation to other | |
other: f64, | |
} | |
/// Defines set of target allocations | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct GlidePath { | |
/// List of target allocations | |
pub target_allocations: Vec<TargetAllocation>, | |
} | |
/// Specifies a desired allocation for a specific year | |
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] | |
pub struct TargetAllocation { | |
/// Year for an allocation | |
pub year: Year, | |
/// A basic target allocation for a specific year | |
pub basic_allocation: BasicAllocation, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% macro money_row(row, show_empty) %} | |
{% for cell in row %} | |
<td style="text-align:right">{{ cell | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro money_row %} | |
{% macro qualified_dividends(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.taxable_distributions.qualified | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro qualified_dividends %} | |
{% macro unqualified_dividends(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.taxable_distributions.unqualified | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro unqualified_dividends %} | |
{% macro capital_gain_distributions(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.taxable_distributions.capital_gain_distribution | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro capital_gain_distributions %} | |
{% macro interest(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.taxable_distributions.interest | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro interest %} | |
{% macro reinvested(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.taxable_distributions.reinvested | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro reinvested %} | |
{% macro disbursed(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.taxable_distributions.disbursed | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro disbursed %} | |
{# sheltered versions #} | |
{% macro sheltered_qualified_dividends(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_distributions.qualified | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro sheltered_qualified_dividends %} | |
{% macro sheltered_unqualified_dividends(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_distributions.unqualified | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro sheltered_unqualified_dividends %} | |
{% macro sheltered_capital_gain_distributions(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_distributions.capital_gain_distribution | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro sheltered_capital_gain_distributions %} | |
{% macro sheltered_interest(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_distributions.interest | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro sheltered_interest %} | |
{% macro sheltered_reinvested(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_distributions.reinvested | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro sheltered_reinvested %} | |
{% macro sheltered_disbursed(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_distributions.disbursed | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro sheltered_disbursed %} | |
{# end sheltered versions #} | |
{% macro long_term_capital_gains_tax(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.fed_tax_statement.long_term_capital_gains_tax | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro long_term_capital_gains_tax %} | |
{% macro long_term_capital_gains(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.tax_inputs.long_term_capital_gains | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro long_term_capital_gains %} | |
{% macro long_term_capital_gains_hurdle(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.long_term_capital_gains_hurdle | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro long_term_capital_gains_hurdle %} | |
{% macro passive_income(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.tax_inputs.passive_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro passive_income %} | |
{% macro portfolio_income(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.tax_inputs.portfolio_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro portfolio_income %} | |
{% macro total_income(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.total_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro total_income %} | |
{% macro ordinary_income(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.tax_inputs.ordinary_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro ordinary_income %} | |
{% macro earned_income(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.tax_inputs.earned_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro earned_income %} | |
{% macro agi(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.adjusted_gross_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro agi %} | |
{% macro retirement_deductions(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.deductible_retirement_investment | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro retirement_deductions %} | |
{% macro sheltered_long_term_capital_gains(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" class="table-info">{{worksheet.netting.sheltered_long_term_capital_gain | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro long_term_capital_gains %} | |
{% macro prior_losses_available(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.prior_losses_available | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro prior_losses_available %} | |
{% macro losses_offsetting_ordinary_income(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.losses_offsetting_ordinary_income | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro losses_offsetting_ordinary_income %} | |
{% macro losses_offsetting_gains(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.losses_offsetting_gains | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro losses_offsetting_gains %} | |
{% macro remaining_losses(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.fed_tax_statement.remaining_losses_available | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro remaining_losses %} | |
{% macro end_balances(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.period_balance.end_balance | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro end_balances %} | |
{% macro tax_basis(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ worksheet.fed_tax_statement.tax_basis | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro tax_basis %} | |
{% macro tax_bill(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.fed_tax_statement.tax_bill | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro tax_bill %} | |
{% macro total_tax_bill(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right; border-bottom-style: solid;">{{ -1.0 * worksheet.fed_tax_statement.total_tax_bill | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro total_tax_bill %} | |
{% macro social_security_tax(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.fed_tax_statement.social_security_tax | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro social_security_tax %} | |
{% macro medicare_tax(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.fed_tax_statement.medicare_tax | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro medicare_tax %} | |
{% macro standard_deduction(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.fed_tax_statement.standard_deduction | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro standard_deduction %} | |
{% macro inflows(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.inflows | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro inflows %} | |
{% macro outflows(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ 0.0 - worksheet.netting.outflows | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro rmd(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.required_minimum_distribution | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro rmd %} | |
{% macro retirement_contributions(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.retirement_investment.employee_contribution | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro retirement_contributions %} | |
{% macro employer_match(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.retirement_investment.employer_match | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro employer_match %} | |
{% macro college_penalties(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.penalties.college_irs529_penalty | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro college_penalties %} | |
{% macro early_withdrawal_penalty(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.penalties.early_withdrawal_penalty | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro early_withdrawal_penalty %} | |
{% macro health_care_penalty(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ -1.0 * worksheet.penalties.health_care_penalty | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro health_care_penalty %} | |
{% macro net_flows(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.net_flows | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro summary_start_balances(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.period_balance.start_balance | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro summary_end_balances(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.period_balance.end_balance | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro summary_balance_with_growth(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{worksheet.netting.balance_with_growth | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro remaining_shortfalls(worksheets) %} | |
{% for worksheet in worksheets %} | |
{% if worksheet.remaining_shortfall > 0.0 %} | |
<td style="text-align:right" class="table-danger"> | |
{% else %} | |
<td style="text-align:right"> | |
{% endif %} | |
{{worksheet.remaining_shortfall | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro year_headers(worksheets) %} | |
{% for worksheet in worksheets %} | |
<th style="text-align:right"> | |
{{ worksheet.year }} | |
{% if worksheet.primary_owner_age %} | |
<div style="whitespace: nowrap">(Age:{{ worksheet.primary_owner_age }})</div> | |
{% endif %} | |
</th> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro marginal_tax_rates(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ worksheet.fed_tax_statement.marginal_tax_rate | round(precision=2) | as_percent }}</td> | |
{% endfor %} | |
{% endmacro marginal_tax_rates %} | |
{% macro as_pct_or_null(v) %} | |
{% if v == 0 %} | |
_ | |
{% else %} | |
{{ v | as_percent }} | |
{% endif %} | |
{% endmacro as_pct_or_null %} | |
{% macro stock_allocation(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ self::as_pct_or_null(v=worksheet.basic_allocation.stock) }}</td> | |
{% endfor %} | |
{% endmacro stock_allocation %} | |
{% macro bond_allocation(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ self::as_pct_or_null(v=worksheet.basic_allocation.bond) }}</td> | |
{% endfor %} | |
{% endmacro bond_allocation %} | |
{% macro cash_allocation(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ self::as_pct_or_null(v=worksheet.basic_allocation.cash) }}</td> | |
{% endfor %} | |
{% endmacro cash_allocation %} | |
{% macro other_allocation(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right">{{ self::as_pct_or_null(v=worksheet.basic_allocation.other) }}</td> | |
{% endfor %} | |
{% endmacro other_allocation %} | |
{% macro effective_tax_rates(worksheets) %} | |
{% for worksheet in worksheets %} | |
<td style="text-align:right" nowrap> | |
{% set total_income = worksheet.fed_tax_statement.total_income + | |
worksheet.fed_tax_statement.tax_inputs.qualified_dividends + | |
worksheet.fed_tax_statement.tax_inputs.long_term_capital_gains | |
%} | |
{% if worksheet.fed_tax_statement.total_tax_bill > 0.0 and total_income > 0.0 %} | |
{% set effective_rate = worksheet.fed_tax_statement.total_tax_bill / total_income %} | |
{{ effective_rate | round(precision=6) | as_percent }} | |
{% else %} | |
__ | |
{% endif %} | |
</td> | |
{% endfor %} | |
{% endmacro outflows %} | |
{% macro label_row(label) %} | |
<tr> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td nowrap><h5>{{ label }}</h5></td> | |
<td style="border-right: 2px solid blue;"></td> | |
</tr> | |
{% endmacro end_balance_detail_row %} | |
{% macro end_balance_detail_row(label, table_row) %} | |
<tr> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td style="text-indent: 20px" nowrap><em>{{ label }}</em></td> | |
<td style="border-right: 2px solid blue;"></td> | |
<td nowrap></td> | |
{{ table_row | safe }} | |
</tr> | |
{% endmacro end_balance_detail_row %} | |
{% macro end_balance_detail_inset_row(label, table_row) %} | |
<tr> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td style="text-indent: 30px" nowrap><em>{{ label }}</em></td> | |
<td style="border-right: 2px solid blue;"></td> | |
<td nowrap></td> | |
{{ table_row | safe }} | |
</tr> | |
{% endmacro end_balance_detail_inset_row %} | |
{% macro end_balance_detail_double_inset_row(label, table_row) %} | |
<tr> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td style="text-indent: 60px" nowrap><em>{{ label }}</em></td> | |
<td style="border-right: 2px solid blue;"></td> | |
<td nowrap></td> | |
{{ table_row | safe }} | |
</tr> | |
{% endmacro end_balance_detail_double_inset_row %} | |
{% macro end_balance_summary_row(label, table_row) %} | |
<tr> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td nowrap><h5>{{ label }}</h5></td> | |
<td style="border-right: 2px solid blue";></td> | |
<td nowrap></td> | |
{{ table_row | safe }} | |
</tr> | |
{% endmacro end_balance_summary_row %} | |
{% macro net_worth_row(pv_end_value, worksheets) %} | |
<tr class="table-warning"> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td>_</td> | |
<td><h5>Net Worth</h5></td> | |
<td style="text-align:right; border-right: 2px solid blue;">{{ pv_end_value | round(precision=0) | as_money}}</td> | |
{% for worksheet in worksheets | slice(start=0, end=1) %} | |
<td style="text-align:right;">{{ worksheet.netting.period_balance.start_balance | round(precision=0) | as_money }}</td> | |
{% endfor %} | |
{{ self::end_balances(worksheets=worksheets) | safe }} | |
</tr> | |
{% endmacro net_worth_row %} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Slowdown does seem to be in tera processing