-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathcommon.py
More file actions
138 lines (107 loc) · 4.34 KB
/
common.py
File metadata and controls
138 lines (107 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#
# Copyright (c) 2024 LateGenXer
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
import math
import streamlit as st
import streamlit.components.v1 as components
import environ
from typing import Any
from data.rpi import RPI
# https://docs.streamlit.io/library/api-reference/utilities/st.set_page_config
def set_page_config(page_title, page_icon=":material/savings:", layout="centered", initial_sidebar_state="auto"):
st.set_page_config(
page_title=page_title,
page_icon=page_icon,
layout=layout,
initial_sidebar_state=initial_sidebar_state,
menu_items={
"Get help": "https://github.com/LateGenXer/finance/discussions",
"Report a bug": "https://github.com/LateGenXer/finance/issues",
"About": """LateGenXer's financial tools.
https://lategenxer.streamlit.app/
https://github.com/LateGenXer/finance
Copyright (c) 2024 LateGenXer.
""",
}
)
def analytics_html():
# An invisible test marker, used when testing with Selenium to ensure a page ran till the end
st.html('<span id="test-marker" style="display:none"></span>')
# Use https://statcounter.com/ to understand which of the calculators are being
# used, and therefore worthy of further attention.
html = (
'<script type="text/javascript">'
'var sc_project=13036387; '
'var sc_invisible=1; '
'var sc_security="3699fd22"; '
'</script>'
'<script type="text/javascript" src="https://www.statcounter.com/counter/counter.js" async></script>'
'<noscript>'
'<div class="statcounter">'
'<a title="Statcounter" href="https://statcounter.com/" target="_blank">'
'<img class="statcounter" src="https://c.statcounter.com/13036387/0/3699fd22/1/" alt="Statcounter" referrerPolicy="no-referrer-when-downgrade">'
'</a>'
'</div>'
'</noscript>'
if environ.production else
'<div class="statcounter">'
'</div>'
)
components.html(html)
@st.cache_data(ttl=1*60*60, show_spinner='Getting latest RPI data...')
def get_latest_rpi():
return RPI()
def rpi_hash(rpi_series: RPI):
assert rpi_series.ref_year == RPI.ref_year
return hash(tuple(rpi_series.series))
@st.cache_data(ttl=30*60, hash_funcs={RPI: rpi_hash}, show_spinner='Getting issued gilts...')
def get_issued_gilts(rpi_series):
from gilts.gilts import Issued
return Issued(rpi_series=rpi_series)
@st.cache_data(ttl=30*60, show_spinner='Getting latest gilt close prices...')
def get_latest_gilt_close_prices():
from gilts.gilts import GiltPrices
return GiltPrices.from_last_close()
@st.cache_data(ttl=5*60, show_spinner='Getting latest gilt offer prices...')
def get_latest_gilt_offer_prices():
from gilts.gilts import GiltPrices
return GiltPrices.from_latest(kind='offer')
def plot_yield_curve(df, yTitle, ySeries='Yield', cSeries='TIDM', ois=None):
import altair as alt
xAxisValues = [0, 1, 2, 3, 5, 10, 15, 30, 50]
maxMaturity = int(math.ceil(df['Maturity'].max()))
for v in xAxisValues[1:]:
xDomainMax = v
if v >= maxMaturity:
break
xAxisValues = [v for v in xAxisValues if v <= xDomainMax]
xScale = alt.Scale(zero=True, domain=[0, xDomainMax])
xAxis = alt.Axis(format=".2~f", values=xAxisValues, title="Maturity (years)")
yDomainMin = min(int(math.floor(df[ySeries].min())), 0)
yDomainMax = int(math.ceil(df[ySeries].max() + 0.25))
yScale = alt.Scale(zero=True, domain=[yDomainMin, yDomainMax])
yAxis = alt.Axis(format=".2~f", values=list(range(yDomainMin, yDomainMax + 1)), title=yTitle)
chart:Any = (
alt.Chart(df)
.mark_point()
.encode(
alt.X("Maturity:Q", scale=xScale, axis=xAxis),
alt.Y(ySeries + ":Q", scale=yScale, axis=yAxis),
alt.Color(cSeries + ":N", legend=None),
)
)
if ois is not None:
import pandas as pd
df = pd.DataFrame({'x': ois.xp, 'y': ois.yp * 100.0})
chart = chart + (
alt.Chart(df)
.mark_line(strokeDash=[12, 4], size=1, tooltip='Overnight Index Swaps (OIS) curve', clip=True)
.encode(
x=alt.X("x", scale=xScale, axis=xAxis),
y=alt.Y("y", scale=yScale, axis=yAxis),
color=alt.value("#333333")
)
)
st.altair_chart(chart, width='stretch')