{"id":6979,"date":"2026-10-25T12:37:08","date_gmt":"2026-10-25T12:37:08","guid":{"rendered":"https:\/\/eodhd.com\/financial-academy\/?p=6979"},"modified":"2026-10-25T12:37:09","modified_gmt":"2026-10-25T12:37:09","slug":"detecting-anomalies-across-correlated-assets-with-anomalybert-in-python","status":"publish","type":"post","link":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python","title":{"rendered":"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A worked example using EODHD data and a self-supervised Transformer for multivariate time-series anomaly detection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A typical anomaly-detection example in finance looks at a single price series in isolation \u2014 a spike, a gap, a sudden jump in volatility. But some of the most useful signals only show up in the <em>relationship<\/em> between two or more series: two normally co-moving stocks suddenly diverging, a hedge that stops hedging, a spread that breaks its historical pattern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This post introduces <strong>AnomalyBERT<\/strong>, the self-supervised Transformer for multivariate time-series anomaly detection proposed in Jeong et al. (2023), and walks through a small, illustrative application: computing an anomaly-score time series for the pair <strong>Coca-Cola (KO)<\/strong> and <strong>PepsiCo (PEP)<\/strong>, using daily price data pulled through the EODHD Python API.<\/p>\n\n\n\n<p style=\"text-align: center\"><a class=\"maxbutton-1 maxbutton maxbutton-subscribe-to-api external-css btn\" href=\"https:\/\/eodhd.com\/register\"><span class='mb-text'>Register &amp; Get Data<\/span><\/a><\/p>\n\n\n\n\n\n\n<h2 id=\"h-what-anomalybert-actually-does\" class=\"wp-block-heading\">What AnomalyBERT actually does<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AnomalyBERT is trained <strong>without labeled anomalies<\/strong>. Instead, it learns by corrupting its own input: during training, random segments of a time-series window are replaced with one of four synthetic \u201coutlier\u201d patterns \u2014 a blended segment, a flattened segment, a lengthened or shortened segment, an injected spike \u2014 and the model is trained to recognize which timesteps were corrupted. Because the model never sees real labels, this works on any multivariate series you can supply, with no annotated anomaly dataset required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Input.<\/strong> A window of multivariate time series<\/p>\n\n\n\n<p><img decoding=\"async\" alt=\"Input window X: a matrix of N time steps by D channels\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Math_Input_Window_X_Definition.png\" style=\"width:5.51em;max-width:100%;height:auto;display:block;margin:16px auto\"><\/p>\n\n<p>where <img decoding=\"async\" alt=\"N: the window length\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Math_Window_Length_N.png\" style=\"height:0.8281em;vertical-align:0em;display:inline\"> is the window length and <img decoding=\"async\" alt=\"D: the number of channels\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Math_Num_Channels_D.png\" style=\"height:0.8281em;vertical-align:-0.0052em;display:inline\"> the number of channels. The window is split into patches of consecutive timesteps; a linear embedding layer combines the channels within each patch, and a Transformer encoder then applies self-attention across the sequence of patches (that is, across time).<\/p>\n\n<p><strong>Output.<\/strong> A per-timestep anomaly score<\/p>\n\n<p><img decoding=\"async\" alt=\"Anomaly score a for time steps t0 to t1: one value between 0 and 1 for each time step\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Math_Anomaly_Score_Definition.png\" style=\"width:6.9em;max-width:100%;height:auto;display:block;margin:16px auto\"><\/p>\n\n<p>produced by averaging predictions from overlapping sliding windows across the full series. A higher score means the point looked\nmore \u201ccorrupted\u201d in the sense the model learned during training \u2014 in practice, more unusual relative to the patterns\n(including the cross-series relationship) that dominate the training data.<\/p>\n\n\n\n<p class=\"bordered_paragraph wp-block-paragraph\"><strong>Note on pretrained checkpoints.<\/strong> The <a href=\"https:\/\/github.com\/Jhryu30\/AnomalyBERT\" target=\"_blank\" rel=\"noreferrer noopener\">official implementation<\/a> ships checkpoints trained on standard industrial benchmarks (SMAP, MSL, SWaT, WADI). Those don\u2019t transfer to financial data \u2014 applying the method to a new pair of series, as below, means training your own (small) model on that series.<\/p>\n\n\n\n<p class=\"bordered_paragraph wp-block-paragraph\">1. Use the \u201cdemo\u201d API key to test our data from a limited set of tickers without registering: AAPL.US | TSLA.US | VTI.US | AMZN.US | BTC-USD | EUR-USD. Real-Time Data and all of the APIs (except Bulk) are included without API calls limitations with these tickers and the demo key.<br>2. Register to get your free API key (limited to 20 API calls per day) with access to: <a href=\"https:\/\/eodhd.com\/financial-apis\/api-for-historical-data-and-volumes\" target=\"_blank\" rel=\"noreferrer noopener\">End-Of-Day Historical Data<\/a> with only the past year for any ticker, and the <a href=\"https:\/\/eodhd.com\/financial-apis\/exchanges-api-list-of-tickers-and-trading-hours\" target=\"_blank\" rel=\"noreferrer noopener\">List of tickers per Exchange<\/a>.<br>3. To unlock your API key, we recommend to choose the subscription plan which covers your needs.<\/p>\n\n\n\n<p style=\"text-align: center\"><a class=\"maxbutton-1 maxbutton maxbutton-subscribe-to-api external-css btn\" href=\"https:\/\/eodhd.com\/register\"><span class='mb-text'>Register &amp; Get Data<\/span><\/a><\/p>\n\n\n\n<h2 id=\"h-pulling-paired-data-via-the-eodhd-api\" class=\"wp-block-heading\">Pulling paired data via the EODHD API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We pull daily adjusted-close prices for KO and PEP going back to 2018, using EODHD\u2019s<strong> <a href=\"https:\/\/eodhd.com\/financial-apis\/api-for-historical-data-and-volumes\" target=\"_blank\" rel=\"noreferrer noopener\">\/eod<\/a> <\/strong>endpoint. Note that this example needs a subscription plan with full end-of-day history: the demo key covers only a few tickers and the free key only the past year, so neither will work for KO.US and PEP.US from 2018:<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code\"><code class=\"\">import os\nimport requests\nimport pandas as pd\n\ndef fetch_eod(ticker, start=\"2018-01-01\", end=None):\n    token = os.getenv(\"EODHD_API_TOKEN\")\n    url = f\"https:\/\/eodhd.com\/api\/eod\/{ticker}\"\n    params = {\"api_token\": token, \"period\": \"d\", \"fmt\": \"json\", \"from\": start}\n    if end:\n        params[\"to\"] = end\n    resp = requests.get(url, params=params, timeout=30)\n    resp.raise_for_status()\n    df = pd.DataFrame(resp.json())\n    df[\"date\"] = pd.to_datetime(df[\"date\"])\n    return df.set_index(\"date\")\n\nko  = fetch_eod(\"KO.US\")\npep = fetch_eod(\"PEP.US\")<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">AnomalyBERT operates on a multivariate matrix, so we build the two-channel input from <strong>standardized daily log-returns<\/strong> of both series rather than raw prices \u2014 returns are closer to stationary, which matters for a degradation scheme built around detecting deviations from a roughly stable pattern:<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code\"><code class=\"\">import numpy as np\n\ndf = pd.DataFrame({\"KO\": ko[\"adjusted_close\"], \"PEP\": pep[\"adjusted_close\"]}).dropna()\nlog_ret = np.log(df \/ df.shift(1)).dropna()\n\nmu, sigma = log_ret.mean(), log_ret.std()\nX = ((log_ret - mu) \/ sigma).values.astype(np.float32)   # shape (T, 2)\ndates = log_ret.index<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<h2 id=\"h-building-and-training-the-model\" class=\"wp-block-heading\">Building and training the model<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The full AnomalyBERT architecture and training pipeline is built for large benchmark datasets and long training runs (up to 150,000 steps in the paper). For an illustrative example like this one, a much smaller version captures the same idea: patch embedding, a shallow Transformer encoder, and a lightweight head producing one anomaly logit per timestep. One simplification worth flagging: the paper injects positional information via a learned <em>relative<\/em> position bias added to each attention matrix, and explicitly avoids absolute position embeddings; this compact version uses a plain learned absolute positional embedding instead, which is simpler to implement but not what the paper does.<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code\"><code class=\"\">import torch\nimport torch.nn as nn\n\nPATCH, WINDOW, D_MODEL, N_HEADS, N_LAYERS = 4, 256, 64, 4, 3\nN_PATCHES = WINDOW \/\/ PATCH\n\nclass AnomalyBERTLite(nn.Module):\n    def __init__(self, n_channels, patch, d_model, n_heads, n_layers, n_patches):\n        super().__init__()\n        self.patch = patch\n        self.embed = nn.Linear(patch * n_channels, d_model)\n        self.pos = nn.Parameter(torch.randn(1, n_patches, d_model) * 0.02)\n        enc_layer = nn.TransformerEncoderLayer(\n            d_model=d_model, nhead=n_heads, dim_feedforward=4 * d_model,\n            dropout=0.1, batch_first=True, activation=\"gelu\")\n        self.encoder = nn.TransformerEncoder(enc_layer, num_layers=n_layers)\n        self.head = nn.Sequential(nn.Linear(d_model, d_model), nn.GELU(), nn.Linear(d_model, patch))\n\n    def forward(self, x):\n        B, T, C = x.shape\n        patches = x.reshape(B, T \/\/ self.patch, self.patch * C)\n        h = self.encoder(self.embed(patches) + self.pos)\n        return self.head(h).reshape(B, T)<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">Training injects one of three synthetic outlier types \u2014 a simplified subset of the paper\u2019s four \u2014 into random segments of random training windows, and optimizes the model to flag the corrupted timesteps:<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code\"><code class=\"\">def degrade(window):\n    w, label = window.copy(), np.zeros(len(window), dtype=np.float32)\n    if np.random.rand() &lt; 0.3:\n        return w, label  # some windows stay clean\n    seg_len = np.random.randint(PATCH * 2, PATCH * 12)\n    start = np.random.randint(0, len(w) - seg_len)\n    end = start + seg_len\n    kind = np.random.choice([\"soft_replace\", \"uniform\", \"peak\"])\n    if kind == \"soft_replace\":\n        alt = np.random.randint(0, len(w) - seg_len)\n        alpha = np.random.uniform(0.5, 1.0)\n        w[start:end] = (1 - alpha) * w[start:end] + alpha * w[alt:alt + seg_len]\n    elif kind == \"uniform\":\n        w[start:end] = np.random.uniform(-1, 1, size=(1, w.shape[1]))\n    else:\n        idx = np.random.randint(start, end)\n        w[idx] += np.random.choice([-1, 1]) * np.random.uniform(3, 6)\n    label[start:end] = 1.0\n    return w, label<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">Training then samples random windows from the standardized series, degrades each one, and fits the model with a binary cross-entropy loss that up-weights the positive class (<code style=\"display:inline;background:#25394d;color:#ffffff;padding:2px 6px;border-radius:4px;white-space:nowrap\">pos_weight=5<\/code>). The seeds are fixed so the run is reproducible; without them, the exact scores \u2014 and which dates rank highest \u2014 will vary from run to run:<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code\"><code class=\"\">torch.manual_seed(7)\nnp.random.seed(7)\n\nmodel = AnomalyBERTLite(X.shape[1], PATCH, D_MODEL, N_HEADS, N_LAYERS, N_PATCHES)\n\ndef sample_batch(batch_size):\n    xs, ys = [], []\n    for _ in range(batch_size):\n        start = np.random.randint(0, X.shape[0] - WINDOW)\n        w_deg, lbl = degrade(X[start:start + WINDOW])\n        xs.append(w_deg)\n        ys.append(lbl)\n    return (torch.tensor(np.stack(xs), dtype=torch.float32),\n            torch.tensor(np.stack(ys), dtype=torch.float32))\n\nN_STEPS, BATCH_SIZE = 800, 32\noptim = torch.optim.AdamW(model.parameters(), lr=3e-4)\nloss_fn = nn.BCEWithLogitsLoss(pos_weight=torch.tensor(5.0))\n\nmodel.train()\nfor step in range(1, N_STEPS + 1):\n    xb, yb = sample_batch(BATCH_SIZE)\n    loss = loss_fn(model(xb), yb)\n    optim.zero_grad()\n    loss.backward()\n    optim.step()<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">A few hundred gradient steps is enough for the loss to start flattening out, and by 800 steps \u2014 with the positive class up-weighted, since corrupted timesteps are a minority within each window \u2014 it\u2019s converged: the full run takes on the order of one to two minutes on a laptop CPU (about 51 seconds in my own run; it varies by machine).<\/p>\n\n\n\n<h2 id=\"h-reading-the-anomaly-score\" class=\"wp-block-heading\">Reading the anomaly score<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After training, we slide the model across the full KO\/PEP history with a stride shorter than the window, and average the overlapping predictions for each date \u2014 the same sliding-window aggregation used in the original paper:<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code\"><code class=\"\">model.eval()\nSTRIDE = 16\nT_full = X.shape[0]\nscore_sum = np.zeros(T_full, dtype=np.float32)\nscore_cnt = np.zeros(T_full, dtype=np.float32)\n\nwith torch.no_grad():\n    for start in range(0, T_full - WINDOW + 1, STRIDE):\n        w = X[start:start + WINDOW]\n        xb = torch.tensor(w[None, :, :], dtype=torch.float32)\n        probs = torch.sigmoid(model(xb)[0]).numpy()\n        score_sum[start:start + WINDOW] += probs\n        score_cnt[start:start + WINDOW] += 1\n\nvalid = score_cnt &gt; 0\nanomaly_score = np.full(T_full, np.nan, dtype=np.float32)\nanomaly_score[valid] = score_sum[valid] \/ score_cnt[valid]\n\nresult = pd.DataFrame({\"KO_close\": df[\"KO\"].reindex(dates),\n                       \"PEP_close\": df[\"PEP\"].reindex(dates),\n                       \"anomaly_score\": anomaly_score}, index=dates)<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">The result is a daily anomaly-score curve alongside the two price series:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"605\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-1024x605.png\" alt=\"Line chart comparing KO and PEP adjusted closing prices from 2018 to 2026 with an AnomalyBERT-lite anomaly score plotted below\" class=\"wp-image-6985\" srcset=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-1024x605.png 1024w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-300x177.png 300w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-768x454.png 768w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-1536x908.png 1536w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-60x35.png 60w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close-150x89.png 150w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Chart_KO_vs_PEP_Adjusted_Close.png 1650w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Top: KO and PEP adjusted close, 2018\u20132026. Bottom: the resulting anomaly score (min-max scaled for readability), with vertical lines marking the five highest-scoring dates (four in January 2022 and one in October 2021; the other five of the top ten, including the May 2026 spike discussed below, are not marked).<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">None of the ten highest-scoring dates coincide with either stock\u2019s single largest daily move in isolation \u2014 those sit elsewhere in the history entirely. The clearest case of an actual co-movement breakdown is mid-May 2026: the 20-day rolling KO\/PEP correlation drops to between its 8th and 15th percentile over the sample, with PEP falling about 1.7% on May 13 against a nearly flat KO. (Those three dates sit at the very tail of the series, though, where sliding-window coverage thins to a third of the usual count, so the scores there are noisier than most.) The other flagged dates \u2014 four in January 2022, two in October 2021 and one in August 2021 \u2014 don\u2019t show the same clean divergence signature: correlation and returns on those days are unremarkable by comparison. That\u2019s a fair reminder that a small, illustrative model like this one will flag some dates for reasons that don\u2019t reduce to one tidy story; the design intent of a multivariate score over a univariate one \u2014 flagging the <em>relationship<\/em>, not just the level of either series \u2014 doesn\u2019t mean every flagged date demonstrates it equally well. All of this refers to data through 21 September 2026; re-running the code later, on a longer sample, will shift the ranking somewhat.<\/p>\n\n\n\n<h2 id=\"h-where-this-is-useful-in-practice\" class=\"wp-block-heading\">Where this is useful in practice<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For a pairs-trading or relative-value setup, a score like this is naturally read as an early-warning or regime-change signal: a spike says \u201cthese two, which normally move together, are currently not behaving normally relative to each other\u201d \u2014 worth a closer look before sizing or holding a spread position, rather than a buy\/sell signal by itself. The same approach extends directly beyond equity pairs \u2014 a stock against its sector ETF, two legs of an FX cross, or (closer to some of my own current research) a DEX and CEX funding rate that are supposed to converge.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The categories below describe how a <em>validated<\/em> score would generally be read in practice \u2014 not a verdict on any particular date from the small, illustrative model above, where (as the previous section showed) not every flagged date tells an equally clean story.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"220\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-1024x220.png\" alt=\"Table summarizing how to interpret the AnomalyBERT-lite anomaly score for the KO\/PEP pair: low score, isolated spike, or sustained elevated score\" class=\"wp-image-6986\" srcset=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-1024x220.png 1024w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-300x64.png 300w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-768x165.png 768w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-1536x330.png 1536w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-2048x440.png 2048w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-60x13.png 60w, https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/AnomalyBERT_Table_Signal_Interpretation-150x32.png 150w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<div style=\"height:12px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">One resolution caveat: every synthetic degradation used in training here \u2014 including the single-point \u201cpeak noise\u201d type \u2014 labels an 8\u201347-day segment as anomalous, so this particular model isn\u2019t actually trained to tell a true one-day event apart from a multi-day one. Treat the isolated-spike\/sustained-elevated split above as a general framework for reading this kind of score, not a distinction this specific model is calibrated to make.<\/p>\n\n\n\n<h2 id=\"h-conclusion\" class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AnomalyBERT\u2019s core contribution \u2014 learning to flag anomalies from synthetic self-supervision rather than labeled data \u2014 makes it straightforward to apply to a new multivariate series, including financial ones, without an existing anomaly dataset. The example above is deliberately small: a compact model, a short training run, and a well-known, liquid equity pair chosen for clarity rather than realism. Applying this seriously to a real pairs-trading or risk-monitoring workflow would call for a properly tuned architecture, a validation methodology for threshold selection, and testing across a wider set of pairs and regimes than shown here.<\/p>\n\n\n\n<p class=\"bordered_paragraph wp-block-paragraph\"><strong>A note on the result above.<\/strong> The anomaly score here is sensitive to training hyperparameters \u2014 window size, patch size, and how heavily the (rare) synthetic anomaly class is weighted during training all visibly shift which dates score highest. It also has two methodological shortcuts worth flagging: the log-returns are standardized using the mean and standard deviation of the <em>entire<\/em> series rather than a rolling or expanding window, so later statistics leak slightly into earlier points; and the model is trained and scored on the same data, with no held-out period. Both are fine for a short, illustrative walkthrough like this one, but either would need addressing \u2014 rolling standardization and a proper train\/test split \u2014 before treating the resulting score as a validated signal.<\/p>\n\n\n\n<p style=\"text-align: center\"><a class=\"maxbutton-1 maxbutton maxbutton-subscribe-to-api external-css btn\" href=\"https:\/\/eodhd.com\/register\"><span class='mb-text'>Register &amp; Get Data<\/span><\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<p class=\"wp-block-paragraph\">This article is for illustrative and educational purposes only and does not constitute investment advice. The examples are simplified, are based on limited data samples, and have not been validated for trading or risk-management use. Past results do not guarantee future performance. Always conduct independent research, backtest thoroughly, and consult a qualified professional before making investment decisions.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 id=\"h-references\" class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Jeong, Y., Yang, E., Ryu, J. H., Park, I., &amp; Kang, M. (2023). <em>AnomalyBERT: Self-supervised transformer for time series anomaly detection using data degradation scheme<\/em>. arXiv. <a href=\"https:\/\/arxiv.org\/abs\/2305.04468\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/arxiv.org\/abs\/2305.04468<\/a><\/li>\n\n\n\n<li>EODHD. (n.d.). <a href=\"https:\/\/eodhd.com\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>EODHD Financial Data APIs<\/em><\/a> [Data set].<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>A typical anomaly-detection example in finance looks at a single price series in isolation \u2014 a spike, a gap, a sudden jump in volatility. But some of the most useful signals only show up in the <em>relationship<\/em> between two or more series: two normally co-moving stocks suddenly diverging, a hedge that stops hedging, a spread that breaks its historical pattern.<\/p>\n","protected":false},"author":35,"featured_media":6996,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[42],"tags":[],"coding-language":[30],"ready-to-go-solution":[],"qualification":[32],"financial-apis-category":[],"financial-apis-manuals":[],"class_list":["post-6979","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stocks-data-analysis-examples","coding-language-python","qualification-guru","has_thumb"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v21.9 (Yoast SEO v26.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python | EODHD APIs Academy<\/title>\n<meta name=\"description\" content=\"Learn how AnomalyBERT, a self-supervised Transformer, flags anomalies in correlated asset pairs like KO\/PEP using Python and the EODHD API.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python\" \/>\n<meta property=\"og:description\" content=\"Detect anomalies across correlated assets with AnomalyBERT in Python: train a small Transformer on KO and PEP returns from EODHD data.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\" \/>\n<meta property=\"og:site_name\" content=\"Financial Academy\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/eodhistoricaldata\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-25T12:37:08+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-25T12:37:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1260\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dr Krzysztof Ozimek\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@EOD_data\" \/>\n<meta name=\"twitter:site\" content=\"@EOD_data\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dr Krzysztof Ozimek\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#article\",\"isPartOf\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\"},\"author\":{\"name\":\"Dr Krzysztof Ozimek\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd\"},\"headline\":\"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python\",\"datePublished\":\"2026-10-25T12:37:08+00:00\",\"dateModified\":\"2026-10-25T12:37:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\"},\"wordCount\":1658,\"publisher\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#organization\"},\"image\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage\"},\"thumbnailUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png\",\"articleSection\":[\"Stocks Data Analysis Examples\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\",\"name\":\"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python | EODHD APIs Academy\",\"isPartOf\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage\"},\"image\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage\"},\"thumbnailUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png\",\"datePublished\":\"2026-10-25T12:37:08+00:00\",\"dateModified\":\"2026-10-25T12:37:09+00:00\",\"description\":\"Learn how AnomalyBERT, a self-supervised Transformer, flags anomalies in correlated asset pairs like KO\/PEP using Python and the EODHD API.\",\"breadcrumb\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png\",\"contentUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png\",\"width\":2400,\"height\":1260,\"caption\":\"Abstract cover graphic representing AnomalyBERT-lite anomaly detection across correlated assets, showing a price series with a highlighted anomaly spike\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/eodhd.com\/financial-academy\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#website\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/\",\"name\":\"Financial APIs Academy | EODHD\",\"description\":\"Financial Stock Market Academy\",\"publisher\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/eodhd.com\/financial-academy\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#organization\",\"name\":\"EODHD (EOD Historical Data)\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png\",\"contentUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png\",\"width\":159,\"height\":82,\"caption\":\"EODHD (EOD Historical Data)\"},\"image\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/eodhistoricaldata\",\"https:\/\/x.com\/EOD_data\",\"https:\/\/www.reddit.com\/r\/EODHistoricalData\/\",\"https:\/\/eod-historical-data.medium.com\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd\",\"name\":\"Dr Krzysztof Ozimek\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g\",\"caption\":\"Dr Krzysztof Ozimek\"},\"description\":\"Quantitative Finance Educator, Researcher, and Author | Close to 30 years of teaching experience\",\"sameAs\":[\"https:\/\/drkrzysztofozimek.com\",\"https:\/\/www.linkedin.com\/in\/krzysztofozimek\/\"],\"url\":\"https:\/\/eodhd.com\/financial-academy\/author\/krzysztofozimek\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python | EODHD APIs Academy","description":"Learn how AnomalyBERT, a self-supervised Transformer, flags anomalies in correlated asset pairs like KO\/PEP using Python and the EODHD API.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python","og_locale":"en_US","og_type":"article","og_title":"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python","og_description":"Detect anomalies across correlated assets with AnomalyBERT in Python: train a small Transformer on KO and PEP returns from EODHD data.","og_url":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python","og_site_name":"Financial Academy","article_publisher":"https:\/\/www.facebook.com\/eodhistoricaldata","article_published_time":"2026-10-25T12:37:08+00:00","article_modified_time":"2026-10-25T12:37:09+00:00","og_image":[{"width":2400,"height":1260,"url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png","type":"image\/png"}],"author":"Dr Krzysztof Ozimek","twitter_card":"summary_large_image","twitter_creator":"@EOD_data","twitter_site":"@EOD_data","twitter_misc":{"Written by":"Dr Krzysztof Ozimek","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#article","isPartOf":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python"},"author":{"name":"Dr Krzysztof Ozimek","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd"},"headline":"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python","datePublished":"2026-10-25T12:37:08+00:00","dateModified":"2026-10-25T12:37:09+00:00","mainEntityOfPage":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python"},"wordCount":1658,"publisher":{"@id":"https:\/\/eodhd.com\/financial-academy\/#organization"},"image":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage"},"thumbnailUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png","articleSection":["Stocks Data Analysis Examples"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python","url":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python","name":"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python | EODHD APIs Academy","isPartOf":{"@id":"https:\/\/eodhd.com\/financial-academy\/#website"},"primaryImageOfPage":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage"},"image":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage"},"thumbnailUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png","datePublished":"2026-10-25T12:37:08+00:00","dateModified":"2026-10-25T12:37:09+00:00","description":"Learn how AnomalyBERT, a self-supervised Transformer, flags anomalies in correlated asset pairs like KO\/PEP using Python and the EODHD API.","breadcrumb":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#primaryimage","url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png","contentUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png","width":2400,"height":1260,"caption":"Abstract cover graphic representing AnomalyBERT-lite anomaly detection across correlated assets, showing a price series with a highlighted anomaly spike"},{"@type":"BreadcrumbList","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/detecting-anomalies-across-correlated-assets-with-anomalybert-in-python#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/eodhd.com\/financial-academy\/"},{"@type":"ListItem","position":2,"name":"Detecting Anomalies Across Correlated Assets with AnomalyBERT in Python"}]},{"@type":"WebSite","@id":"https:\/\/eodhd.com\/financial-academy\/#website","url":"https:\/\/eodhd.com\/financial-academy\/","name":"Financial APIs Academy | EODHD","description":"Financial Stock Market Academy","publisher":{"@id":"https:\/\/eodhd.com\/financial-academy\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/eodhd.com\/financial-academy\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/eodhd.com\/financial-academy\/#organization","name":"EODHD (EOD Historical Data)","url":"https:\/\/eodhd.com\/financial-academy\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/","url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png","contentUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png","width":159,"height":82,"caption":"EODHD (EOD Historical Data)"},"image":{"@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/eodhistoricaldata","https:\/\/x.com\/EOD_data","https:\/\/www.reddit.com\/r\/EODHistoricalData\/","https:\/\/eod-historical-data.medium.com\/"]},{"@type":"Person","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd","name":"Dr Krzysztof Ozimek","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g","caption":"Dr Krzysztof Ozimek"},"description":"Quantitative Finance Educator, Researcher, and Author | Close to 30 years of teaching experience","sameAs":["https:\/\/drkrzysztofozimek.com","https:\/\/www.linkedin.com\/in\/krzysztofozimek\/"],"url":"https:\/\/eodhd.com\/financial-academy\/author\/krzysztofozimek"}]}},"jetpack_featured_media_url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/09\/Detecting_Anomalies_Across_Correlated_Assets_with_AnomalyBERT.png","jetpack_shortlink":"https:\/\/wp.me\/pdOdVT-1Oz","jetpack_sharing_enabled":true,"acf":[],"_links":{"self":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts\/6979","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/users\/35"}],"replies":[{"embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/comments?post=6979"}],"version-history":[{"count":37,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts\/6979\/revisions"}],"predecessor-version":[{"id":7094,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts\/6979\/revisions\/7094"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/media\/6996"}],"wp:attachment":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/media?parent=6979"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/categories?post=6979"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/tags?post=6979"},{"taxonomy":"coding-language","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/coding-language?post=6979"},{"taxonomy":"ready-to-go-solution","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/ready-to-go-solution?post=6979"},{"taxonomy":"qualification","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/qualification?post=6979"},{"taxonomy":"financial-apis-category","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/financial-apis-category?post=6979"},{"taxonomy":"financial-apis-manuals","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/financial-apis-manuals?post=6979"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}