import%20marimo%0A%0A__generated_with%20%3D%20%220.13.15%22%0Aapp%20%3D%20marimo.App()%0A%0Awith%20app.setup%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20plotly.io%20as%20pio%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20from%20cvxsimulator%20import%20interpolate%0A%0A%20%20%20%20%23%20Ensure%20Plotly%20works%20with%20Marimo%0A%20%20%20%20pio.renderers.default%20%3D%20%22plotly_mimetype%22%0A%20%20%20%20pd.options.plotting.backend%20%3D%20%22plotly%22%0A%0A%20%20%20%20path%20%3D%20mo.notebook_location()%20%2F%20%22public%22%20%2F%20%22Prices_hashed.csv%22%0A%20%20%20%20date_col%20%3D%20%22date%22%0A%0A%20%20%20%20dframe%20%3D%20pl.read_csv(str(path)%2C%20try_parse_dates%3DTrue)%0A%0A%20%20%20%20dframe%20%3D%20dframe.with_columns(pl.col(date_col).cast(pl.Datetime(%22ns%22)))%0A%20%20%20%20dframe%20%3D%20dframe.with_columns(%0A%20%20%20%20%20%20%20%20%5Bpl.col(col).cast(pl.Float64)%20for%20col%20in%20dframe.columns%20if%20col%20!%3D%20date_col%5D%0A%20%20%20%20)%0A%20%20%20%20prices%20%3D%20dframe.to_pandas().set_index(date_col).apply(interpolate)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20CTA%203.0%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20warnings%0A%0A%20%20%20%20%23%20Suppress%20noisy%20warnings%0A%20%20%20%20warnings.simplefilter(action%3D%22ignore%22%2C%20category%3DFutureWarning)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20We%20use%20the%20system%3A%0A%20%20%20%20%24%24%5Cmathrm%7BCashPosition%7D%3D%5Cfrac%7Bf(%5Cmathrm%7BPrice%7D)%7D%7B%5Cmathrm%7BVolatility(Returns)%7D%7D%24%24%0A%0A%20%20%20%20This%20is%20very%20problematic%3A%0A%20%20%20%20*%20Prices%20may%20live%20on%20very%20different%20scales%2C%20hence%20trying%20to%20find%20a%0A%20%20%20%20more%20universal%20function%20%24f%24%20is%20almost%20impossible.%20The%20sign-function%20was%0A%20%20%20%20a%20good%20choice%20as%20the%20results%20don't%20depend%20on%20the%20scale%20of%20the%20argument.%0A%20%20%20%20*%20Price%20may%20come%20with%20all%20sorts%20of%20spikes%2Foutliers%2Fproblems.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20We%20need%20a%20simple%20price%20filter%20process%0A%20%20%20%20*%20We%20compute%20volatility-adjusted%20returns%2C%20filter%20them%20and%20compute%20prices%20from%20those%20returns.%0A%20%20%20%20*%20Don't%20call%20it%20Winsorizing%20in%20Switzerland.%20We%20apply%20Huber%20functions.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.function%0Adef%20filter(price%2C%20volatility%3D32%2C%20clip%3D4.2%2C%20min_periods%3D300)%3A%0A%20%20%20%20r%20%3D%20np.log(price).diff()%0A%20%20%20%20vola%20%3D%20r.ewm(com%3Dvolatility%2C%20min_periods%3Dmin_periods).std()%0A%20%20%20%20price_adj%20%3D%20(r%20%2F%20vola).clip(-clip%2C%20clip).cumsum()%0A%20%20%20%20return%20price_adj%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%23%23%23%20Oscillators%0A%20%20%20%20*%20All%20prices%20are%20now%20following%20a%20standard%20arithmetic%20Brownian%0A%20%20%20%20motion%20with%20std%20%241%24.%0A%20%20%20%20*%20What%20we%20want%20is%20the%20difference%20of%20two%20moving%20means%20(exponentially%20weighted)%0A%20%20%20%20to%20have%20a%20constant%20std%20regardless%20of%20the%20two%20lengths.%0A%20%20%20%20*%20An%20oscillator%20is%20the%20**scaled%20difference%20of%20two%20moving%20averages**.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.function%0Adef%20osc(prices%2C%20fast%3D32%2C%20slow%3D96%2C%20scaling%3DTrue)%3A%0A%20%20%20%20diff%20%3D%20prices.ewm(com%3Dfast%20-%201).mean()%20-%20prices.ewm(com%3Dslow%20-%201).mean()%0A%20%20%20%20if%20scaling%3A%0A%20%20%20%20%20%20%20%20%23%20attention%20this%20formula%20is%20forward-looking%0A%20%20%20%20%20%20%20%20%23%20s%20%3D%20diff.std()%0A%20%20%20%20%20%20%20%20%23%20you%20may%20want%20to%20use%0A%20%20%20%20%20%20%20%20f%2C%20g%20%3D%201%20-%201%20%2F%20fast%2C%201%20-%201%20%2F%20slow%0A%20%20%20%20%20%20%20%20s%20%3D%20np.sqrt(1.0%20%2F%20(1%20-%20f%20*%20f)%20-%202.0%20%2F%20(1%20-%20f%20*%20g)%20%2B%201.0%20%2F%20(1%20-%20g%20*%20g))%0A%20%20%20%20%20%20%20%20%23%20or%20a%20moving%20std%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20s%20%3D%201%0A%0A%20%20%20%20return%20diff%20%2F%20s%0A%0A%0A%40app.function%0A%23%20from%20pycta.signal%20import%20osc%0A%0A%23%20take%20two%20moving%20averages%20and%20apply%20tanh%0Adef%20f(price%2C%20slow%3D96%2C%20fast%3D32%2C%20vola%3D96%2C%20clip%3D3)%3A%0A%20%20%20%20%23%20construct%20a%20fake-price%2C%20those%20fake-prices%20have%20homescedastic%20returns%0A%20%20%20%20price_adj%20%3D%20filter(price%2C%20volatility%3Dvola%2C%20clip%3Dclip)%0A%20%20%20%20%23%20compute%20mu%0A%20%20%20%20mu%20%3D%20np.tanh(osc(prices%3Dprice_adj%2C%20fast%3Dfast%2C%20slow%3Dslow))%0A%20%20%20%20return%20mu%20%2F%20price.pct_change().ewm(com%3Dslow%2C%20min_periods%3D300).std()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20%23%20Create%20sliders%20using%20marimo's%20UI%20components%0A%20%20%20%20fast%20%3D%20mo.ui.slider(4%2C%20192%2C%20step%3D4%2C%20value%3D32%2C%20label%3D%22Fast%20Moving%20Average%22)%0A%20%20%20%20slow%20%3D%20mo.ui.slider(4%2C%20192%2C%20step%3D4%2C%20value%3D96%2C%20label%3D%22Slow%20Moving%20Average%22)%0A%20%20%20%20vola%20%3D%20mo.ui.slider(4%2C%20192%2C%20step%3D4%2C%20value%3D32%2C%20label%3D%22Volatility%22)%0A%20%20%20%20winsor%20%3D%20mo.ui.slider(1.0%2C%206.0%2C%20step%3D0.1%2C%20value%3D4.2%2C%20label%3D%22Winsorizing%22)%0A%0A%20%20%20%20%23%20Display%20the%20sliders%20in%20a%20vertical%20stack%0A%20%20%20%20mo.vstack(%5Bfast%2C%20slow%2C%20vola%2C%20winsor%5D)%0A%0A%20%20%20%20return%20fast%2C%20slow%2C%20vola%2C%20winsor%0A%0A%0A%40app.cell%0Adef%20_(fast%2C%20slow%2C%20vola%2C%20winsor)%3A%0A%20%20%20%20from%20cvxsimulator%20import%20Portfolio%0A%0A%20%20%20%20pos%20%3D%201e5%20*%20f(%0A%20%20%20%20%20%20%20%20prices%2C%20fast%3Dfast.value%2C%20slow%3Dslow.value%2C%20vola%3Dvola.value%2C%20clip%3Dwinsor.value%0A%20%20%20%20)%0A%20%20%20%20portfolio%20%3D%20Portfolio.from_cashpos_prices(prices%3Dprices%2C%20cashposition%3Dpos%2C%20aum%3D1e8)%0A%20%20%20%20print(portfolio.sharpe())%0A%20%20%20%20return%20(portfolio%2C)%0A%0A%0A%40app.cell%0Adef%20_(portfolio)%3A%0A%20%20%20%20fig%20%3D%20portfolio.snapshot()%0A%20%20%20%20fig%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
eb8947b44c22e39125347b5efffc5aace7eaeaaa3fd85a8261e7daa08b3fc42e