<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aethan Lee</title>
    <description>The latest articles on DEV Community by Aethan Lee (@aethanlee).</description>
    <link>https://dev.to/aethanlee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4015933%2F942331b7-7455-441a-87a4-d86f6a57a190.png</url>
      <title>DEV Community: Aethan Lee</title>
      <link>https://dev.to/aethanlee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aethanlee"/>
    <language>en</language>
    <item>
      <title>Modeling Bitcoin volatility with a Markov-switching model</title>
      <dc:creator>Aethan Lee</dc:creator>
      <pubDate>Mon, 14 Sep 2026 17:22:37 +0000</pubDate>
      <link>https://dev.to/aethanlee/modeling-bitcoin-volatility-with-a-markov-switching-model-5a6o</link>
      <guid>https://dev.to/aethanlee/modeling-bitcoin-volatility-with-a-markov-switching-model-5a6o</guid>
      <description>&lt;p&gt;A Bitcoin price chart shows the path prices took. For this report, I wanted to estimate how the volatility of daily returns changed along that path.&lt;/p&gt;

&lt;p&gt;I used a Markov-switching model and built the visual report in OWL Compose. The report includes state probabilities, a transition matrix and a comparison between two-state and three-state specifications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://owlcompose.com/works/bitcoin-market-regimes?lang=en&amp;amp;utm_source=dev&amp;amp;utm_medium=social&amp;amp;utm_campaign=bitcoin_regimes" rel="noopener noreferrer"&gt;Explore the full report&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with returns and a fixed cutoff
&lt;/h2&gt;

&lt;p&gt;The input is Binance Spot BTCUSDT daily OHLCV data, using completed UTC candles through September 13, 2026. Daily returns are calculated as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 * ln(close_today / close_yesterday)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I kept weekends and excluded the incomplete daily candle. The training period runs from January 2, 2022 through June 30, 2026: 1,641 daily returns. The holdout contains 75 days, from July 1 through September 13.&lt;/p&gt;

&lt;p&gt;That split matters. Parameters fitted over the entire history would let later observations influence the apparent success of an earlier classification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fit states with different variances
&lt;/h2&gt;

&lt;p&gt;The analysis uses statsmodels MarkovRegression with switching means and variances. Both the two-state and three-state models were fitted using multiple starting values and three random seeds. I retained the converged fit with the highest likelihood for each specification.&lt;/p&gt;

&lt;p&gt;In the two-state model, the fitted daily return standard deviations are about 1.53% and 4.30%. Both means are close to zero, so I label the states by volatility. Large positive and negative returns can both fit the high-volatility state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the probability path visible
&lt;/h2&gt;

&lt;p&gt;For the holdout period, training parameters stay fixed. Filtered probabilities update using returns observed up to each day.&lt;/p&gt;

&lt;p&gt;The report places the most likely state on the price timeline, then shows the full probability series below it. A hard label can change when the probabilities cross 50%; the probability chart shows whether that change was decisive or marginal.&lt;/p&gt;

&lt;p&gt;The January–June portion is explicitly marked as a retrospective training view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the model choice
&lt;/h2&gt;

&lt;p&gt;The three-state model has a slightly lower training BIC. The two-state model has a slightly better mean predictive log score over this holdout. That is useful evidence of sensitivity, rather than proof of a universal winner.&lt;/p&gt;

&lt;p&gt;The score evaluates the probability density assigned to observed returns. It does not measure directional trading accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the assumptions inspectable
&lt;/h2&gt;

&lt;p&gt;The report includes fitted distributions, model parameters, transition probabilities and reproducibility notes. Constant transition probabilities and Gaussian returns remain simplifying assumptions.&lt;/p&gt;

&lt;p&gt;I built OWL Compose, and used it to present this analysis alongside its charts and data. If you work on time-series analysis, the &lt;a href="https://owlcompose.com/works/bitcoin-market-regimes?lang=en&amp;amp;utm_source=dev&amp;amp;utm_medium=social&amp;amp;utm_campaign=bitcoin_regimes" rel="noopener noreferrer"&gt;English report&lt;/a&gt; shows the complete result.&lt;/p&gt;

&lt;p&gt;What would you test next: rolling refits, a different training window, or a heavier-tailed return distribution?&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Keeping an AI-assisted conversion report numerically consistent</title>
      <dc:creator>Aethan Lee</dc:creator>
      <pubDate>Sun, 13 Sep 2026 18:52:40 +0000</pubDate>
      <link>https://dev.to/aethanlee/keeping-an-ai-assisted-conversion-report-numerically-consistent-4p4d</link>
      <guid>https://dev.to/aethanlee/keeping-an-ai-assisted-conversion-report-numerically-consistent-4p4d</guid>
      <description>&lt;p&gt;I'm a software engineer, and data analysis is part of my work. Cleaning data, agreeing on metric definitions, and checking a report against its source numbers are familiar parts of the job.&lt;/p&gt;

&lt;p&gt;I built OWL Compose to help with this workflow. This post walks through the checks behind a user conversion report I made with it. The dataset is simulated and describes a fictional team collaboration product; it contains no customer performance results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the population and observation window
&lt;/h2&gt;

&lt;p&gt;The example covers January–June 2026 signup cohorts, observed through August 1. Each user is assigned to their first acquisition channel. The onboarding funnel follows signup, completed import, and first useful output, in that order, within seven days of signup.&lt;/p&gt;

&lt;p&gt;Week 4 retention counts users active on days 22–28 after signup, divided by the original signup cohort. All six cohorts have completed that window. This makes the comparison meaningful across signup months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculate the total from counts
&lt;/h2&gt;

&lt;p&gt;The six months contain 29,080 signups and 7,486 week 4 active users. The combined retention rate is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7,486 / 29,080 × 100 = 25.7% (rounded)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This calculation weights each cohort by its size. An unweighted average of monthly percentages would give each month equal influence even though the signup counts differ.&lt;/p&gt;

&lt;p&gt;For each month and channel, the report uses the same definitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;activation = first useful output within 7 days / signups
week 4 retention = active users in days 22–28 / signups
spend per week 4 active user = direct acquisition spend / week 4 active users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The spend measure is in CNY. It includes direct acquisition expenses and excludes staffing, product delivery, and service costs. It cannot establish profitability without revenue and the missing costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the aggregate against its segments
&lt;/h2&gt;

&lt;p&gt;January has 3,000 signups and 781 week 4 active users: 26.0% retention. June has 7,180 signups and 1,833 week 4 active users: 25.5%.&lt;/p&gt;

&lt;p&gt;Within each channel, June retention is higher than January retention. Paid ads, the lowest-retention channel in this example, account for a larger share of June signups. Both the channel rates and their weights contribute to the aggregate.&lt;/p&gt;

&lt;p&gt;This is a useful report review: a change in the total can reflect a change in the population mix. The channel breakdown helps explain the arithmetic. It does not establish why users behaved differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the presentation tied to the calculations
&lt;/h2&gt;

&lt;p&gt;In the report, the metric cards, charts, and appendix draw from the same simulated aggregate data. Derived values are calculated from those inputs. The written analysis names the cohort, denominator, and limits of each comparison.&lt;/p&gt;

&lt;p&gt;OWL Compose helps me put those pieces into a readable report with AI. Input quality and metric definitions still need review. A polished chart does not validate either one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://owlcompose.com/works/user-conversion-analysis?lang=en&amp;amp;utm_source=dev&amp;amp;utm_medium=social&amp;amp;utm_campaign=conversion_case_launch" rel="noopener noreferrer"&gt;Explore the complete simulated report&lt;/a&gt;. The public example includes the funnel, channel comparison, retention matrix, and data appendix.&lt;/p&gt;

&lt;p&gt;If you review analytics reports, which consistency check do you run first?&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>ai</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
