{"data_providers":["alto_scoring_engine","tonydee"],"groups":["Ticker data","Scoring","Data providers","Newsletters","Maintenance"],"kinds":{"compute":"Computes in this service","filter":"Skips some items, or stops early","read":"Reads the backoffice, the database or a local file","send":"Sends emails (Brevo)","source":"Fetches from an external source (Yahoo Finance, Google News, altotrades.com)","write":"Writes to the backoffice, the database or a local file"},"parameters":{"data_provider":{"default":"","help":"Empty: every provider","label":"Data provider","type":"provider"},"date":{"default":"","help":"Empty: the endpoint's default (see its note)","label":"Date","type":"date"},"days_back":{"default":1,"help":"The number of days ending at the date; more than 1 runs as a background job","label":"Days","min":1,"type":"int"},"force":{"default":false,"help":"Refresh even closed markets and prices less than 15 minutes old","label":"Force","type":"bool"},"ignore_send_time":{"default":false,"help":"Every subscribed user gets the newsletter of their local date, now","label":"Ignore send time","type":"bool"},"retro_days":{"default":0,"help":"Also recompute this many days before the date","label":"Days before","min":0,"type":"int"},"sync":{"default":true,"help":"Off: compute and save only (sync=false, a dry run)","label":"Post to the backoffice","type":"bool"},"ticker":{"default":"","help":"A ticker code runs synchronously for that ticker; empty runs over every ticker as a background job","label":"Ticker","placeholder":"every ticker","type":"text"}},"pipelines":[{"arguments":{"force":false,"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":{"created_at":"2026-11-15T22:00:00+00:00","error":null,"finished_at":"2026-11-15T22:00:41+00:00","id":"aa62afb0dfba4984b52489488c7eda85","name":"refresh-prices","params":{"force":false,"ticker_code":null},"progress":{"done":983,"total":983},"started_at":"2026-11-15T22:00:00+00:00","status":"succeeded","summary":{"failed":0,"skipped":0,"succeeded":983,"total":983},"trigger":"schedule"},"name":"refresh-prices","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh prices","method":"POST","note":null,"params":["ticker","force"],"path":"/tickers/refresh/price","path_params":{},"warning":null}],"schedule":{"comment":"As before Prefect (every 15 min). Only tickers whose market is open and whose price is older than 15 min are refreshed","cron":"*/15 * * * *","enabled":true,"next_run_at":"2026-11-15T22:15:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Skipped when inactive, outside the market's window (open \u2212 30 min to close + 90 min, weekends unless it trades then) or priced less than 15 min ago. force=true skips this check","each":true,"kind":"filter","label":"Market open, price stale?","links":[],"target":"settings/markets.json"},{"detail":"Daily bars, history(period=7d)","each":true,"kind":"source","label":"Last 7 days","links":[],"target":"Yahoo Finance"},{"detail":"Latest = last close, open = last open, last week = first close","each":true,"kind":"compute","label":"Derive the prices","links":[],"target":null},{"detail":"The whole ticker with its new prices","each":true,"kind":"write","label":"Update the ticker","links":[],"target":"PUT /api-admin/tickers/<id>/"}],"summary":"Latest, open and last-week prices from Yahoo's last 7 days, for the tickers whose market is open and whose price is more than 15 minutes old.","title":"Latest prices","used_by":["data-quality"]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":{"created_at":"2026-11-15T03:00:00+00:00","error":null,"finished_at":"2026-11-15T03:24:33+00:00","id":"f027001a84e14d34b47fcb603713e5d4","name":"refresh-information","params":{"ticker_code":null},"progress":{"done":983,"total":983},"started_at":"2026-11-15T03:00:00+00:00","status":"completed_with_errors","summary":{"failed":21,"skipped":0,"succeeded":962,"total":983},"trigger":"schedule"},"name":"refresh-information","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh information","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/information","path_params":{},"warning":null}],"schedule":{"comment":null,"cron":"0 4 * * *","enabled":true,"next_run_at":"2026-11-16T03:00:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Ticker.info","each":true,"kind":"source","label":"Yahoo info","links":[],"target":"Yahoo Finance"},{"detail":"Targets, recommendation, number of opinions","each":true,"kind":"compute","label":"Analyst fields","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/analyst-ratings"},"pipeline":"refresh-analyst-ratings","relation":"same"}],"target":null},{"detail":"Yahoo keys to backoffice codes (matching_tables.py); unknown keys are appended to a file","each":true,"kind":"compute","label":"Map sector and industry","links":[],"target":"unknown_sectors.txt, unknown_industries.txt"},{"detail":"Names, website, summary, dividend yield and last value, market cap, employees","each":true,"kind":"compute","label":"Profile fields","links":[],"target":null},{"detail":"The whole ticker with its new profile","each":true,"kind":"write","label":"Update the ticker","links":[],"target":"PUT /api-admin/tickers/<id>/"}],"summary":"Company profile, sector and industry, analyst targets, market cap and dividend figures from Yahoo, written on the ticker in the backoffice.","title":"Ticker profile","used_by":["data-quality"]},{"arguments":{"period":"max","ticker_code":null},"group":"Ticker data","items":"ticker","last_run":null,"name":"refresh-price-history","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Full history","method":"POST","note":"period=max","params":["ticker"],"path":"/tickers/refresh/price-history","path_params":{},"warning":null},{"aliases":[],"label":"Last 7 days","method":"POST","note":"period=7d, as scheduled","params":["ticker"],"path":"/tickers/refresh/price-history-latest","path_params":{},"warning":null}],"schedule":{"comment":"Last 7 days of daily prices, after the US close","cron":"30 22 * * 1-5","enabled":true,"next_run_at":"2026-11-16T21:30:00+00:00","params":{"period":"7d"},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"history(period=max or 7d)","each":true,"kind":"source","label":"Daily history","links":[],"target":"Yahoo Finance"},{"detail":"Lower-case columns, YYYY-MM-DD dates","each":true,"kind":"compute","label":"Normalise the rows","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Upload the history","links":[],"target":"POST /api-scheduler/tickers/<id>/historical-prices/"}],"summary":"Daily price history uploaded to the backoffice: the full history, or the last 7 days (what the schedule runs).","title":"Price history","used_by":["data-quality"]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":{"created_at":"2026-11-15T05:00:00+00:00","error":null,"finished_at":null,"id":"026bfe5db0f3496dbbeb722af67b70dc","name":"refresh-news","params":{"ticker_code":null},"progress":{"done":354,"total":983},"started_at":"2026-11-15T05:00:00+00:00","status":"running","trigger":"schedule"},"name":"refresh-news","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh news","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/news-sentiment","path_params":{},"warning":null}],"schedule":{"comment":null,"cron":"0 6 * * *","enabled":true,"next_run_at":"2026-11-16T05:00:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"RSS search on the ticker's name, first 50 articles","each":true,"kind":"source","label":"Google News","links":[],"target":"news.google.com/rss"},{"detail":"EN/FR keyword lexicon with negations: sentiment_label, sentiment_score in [-1, 1]","each":true,"kind":"compute","label":"Score the headlines","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Store the articles","links":[],"target":"POST /api-admin/ticker-news/"}],"summary":"The latest Google News articles about each ticker, each headline scored by keywords, stored in the backoffice.","title":"News and sentiment","used_by":["rescore-news-sentiment","data-quality"]},{"arguments":{"date_from":null,"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":null,"name":"rescore-news-sentiment","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Rescore","method":"POST","note":"date: only the articles dated on or after it (empty: every stored article)","params":["ticker","date"],"path":"/tickers/refresh/news-sentiment-rescore","path_params":{},"warning":null}],"schedule":null,"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Dated on or after the date","each":true,"kind":"read","label":"Stored articles","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/news-sentiment"},"pipeline":"refresh-news","relation":"uses"}],"target":"PostgreSQL ai_tickerdata_altotickernews"},{"detail":"The same keyword scorer as the news refresh","each":true,"kind":"compute","label":"Score them again","links":[],"target":null},{"detail":"Only the articles whose label or score changed are written","each":true,"kind":"filter","label":"Unchanged ones skipped","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Update their sentiment","links":[],"target":"PATCH /api-admin/ticker-news/<id>/"}],"summary":"Scores the stored articles again with the current keywords and updates those whose sentiment changed: the backfill after a deploy or a change of the lexicon. Idempotent.","title":"News sentiment rescore","used_by":[]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":{"created_at":"2026-11-15T01:00:00+00:00","error":null,"finished_at":"2026-11-15T01:08:12+00:00","id":"a1d967a5eb0c4405865aaf5288e8e2e8","name":"refresh-financials","params":{"ticker_code":null},"progress":{"done":983,"total":983},"started_at":"2026-11-15T01:00:00+00:00","status":"succeeded","summary":{"failed":0,"skipped":0,"succeeded":983,"total":983},"trigger":"schedule"},"name":"refresh-financials","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh financials","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/financial-information","path_params":{},"warning":null}],"schedule":{"comment":"Quarterly statements: once a week is enough","cron":"0 2 * * 0","enabled":true,"next_run_at":"2026-11-22T01:00:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"quarterly_income_stmt","each":true,"kind":"source","label":"Quarterly statements","links":[],"target":"Yahoo Finance"},{"detail":"One row per quarter: revenue, net income, diluted EPS\u2026","each":true,"kind":"compute","label":"Map the line items","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Store the statements","links":[],"target":"POST /api-admin/ticker-financials/"}],"summary":"Quarterly income statements from Yahoo, stored in the backoffice.","title":"Financial statements","used_by":["data-quality"]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":{"created_at":"2026-11-15T02:00:00+00:00","error":null,"finished_at":"2026-11-15T02:22:49+00:00","id":"12f63eaea8124c15a94ceab35e2ba836","name":"refresh-analyst-ratings","params":{"ticker_code":null},"progress":{"done":983,"total":983},"started_at":"2026-11-15T02:00:00+00:00","status":"completed_with_errors","summary":{"failed":19,"skipped":0,"succeeded":964,"total":983},"trigger":"schedule"},"name":"refresh-analyst-ratings","part_of":["refresh-information"],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh analyst ratings","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/analyst-ratings","path_params":{},"warning":null}],"schedule":{"comment":"PATCHes the analyst fields of each ticker; refresh-information already writes them daily","cron":"0 3 * * 0","enabled":true,"next_run_at":"2026-11-22T02:00:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Ticker.info","each":true,"kind":"source","label":"Yahoo info","links":[],"target":"Yahoo Finance"},{"detail":null,"each":true,"kind":"filter","label":"No info, nothing written","links":[],"target":null},{"detail":"Price hint, target high/low/mean/median, recommendation mean and key, opinions, average rating","each":true,"kind":"compute","label":"Analyst fields","links":[],"target":null},{"detail":"The backoffice stamps analyst_data_updated_at","each":true,"kind":"write","label":"Patch the analyst fields","links":[],"target":"PATCH /api-admin/tickers/<id>/"}],"summary":"Only the analyst fields of each ticker, patched; refresh-information writes the same fields with the rest of the profile.","title":"Analyst ratings","used_by":[]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":{"created_at":"2026-11-15T02:30:00+00:00","error":null,"finished_at":"2026-11-15T02:41:07+00:00","id":"f1984c9db6b54242a8541b1ec08b9d6b","name":"refresh-dividends","params":{"ticker_code":null},"progress":{"done":983,"total":983},"started_at":"2026-11-15T02:30:00+00:00","status":"succeeded","summary":{"failed":0,"skipped":0,"succeeded":983,"total":983},"trigger":"schedule"},"name":"refresh-dividends","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh dividends","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/dividends","path_params":{},"warning":null}],"schedule":{"comment":"Fails for every ticker until alto_backend has /api-admin/ticker-dividends/","cron":"30 3 * * 0","enabled":true,"next_run_at":"2026-11-22T02:30:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Ticker.dividends","each":true,"kind":"source","label":"Dividend history","links":[],"target":"Yahoo Finance"},{"detail":"[{date, value}]","each":true,"kind":"compute","label":"Dataset","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Store the dividends","links":[],"target":"POST /api-admin/ticker-dividends/"}],"summary":"Each ticker's dividend history from Yahoo, stored in the backoffice. Fails for every ticker until the backoffice deploys its endpoint.","title":"Dividend history","used_by":["data-quality"]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":null,"name":"refresh-calendar","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh calendar","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/calendar","path_params":{},"warning":null}],"schedule":{"comment":"Earnings and ex-dividend dates (stocks only): the newsletters list their signal tickers publishing results within 7 days","cron":"30 6 * * 1-5","enabled":true,"next_run_at":"2026-11-16T05:30:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Inactive tickers, ETFs, indices, crypto, forex and funds are skipped (no Yahoo calendar)","each":true,"kind":"filter","label":"Active stocks only","links":[],"target":null},{"detail":"Ticker.calendar","each":true,"kind":"source","label":"Yahoo calendar","links":[],"target":"Yahoo Finance"},{"detail":"Next earnings date (or window), EPS and revenue estimates, ex-dividend and payment dates","each":true,"kind":"compute","label":"Parse dates and estimates","links":[],"target":null},{"detail":"Earnings dates now passed are added to those of the previous file","each":true,"kind":"read","label":"Keep past publications","links":[],"target":"data/<TICKER>/calendar.json"},{"detail":null,"each":true,"kind":"write","label":"Save the calendar","links":[],"target":"data/<TICKER>/calendar.json"},{"detail":"In one PATCH, only the dates that changed: a future ex-dividend date, an earnings date from today on","each":true,"kind":"write","label":"Next dividend and earnings dates","links":[],"target":"PATCH /api-admin/tickers/<id>/"}],"summary":"Next earnings date and estimates, ex-dividend and payment dates of the active stocks, saved locally (the newsletters list the upcoming earnings); the next earnings date and an announced ex-dividend date go to the backoffice.","title":"Earnings and dividend dates","used_by":["send-newsletters"]},{"arguments":{"ticker_code":null},"group":"Ticker data","items":"ticker","last_run":null,"name":"refresh-sector-industry","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Refresh sector and industry","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/sector-and-industry","path_params":{},"warning":null}],"schedule":null,"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Ticker.info","each":true,"kind":"source","label":"Yahoo info","links":[],"target":"Yahoo Finance"},{"detail":"The backoffice sync is still a TODO","each":true,"kind":"compute","label":"Log sector and industry","links":[],"target":null}],"summary":"Reads the sector and industry from Yahoo and logs them: nothing is written yet. refresh-information is the pipeline that maps and writes them.","title":"Sector and industry (log only)","used_by":[]},{"arguments":{"ticker_code":null},"group":"Scoring","items":"ticker","last_run":null,"name":"compute-scenarios","part_of":["optimize-strategies"],"per_ticker":true,"runs":[{"aliases":[],"label":"Compute scenarios","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/scenarios","path_params":{},"warning":null}],"schedule":{"comment":"After refresh-price-history","cron":"0 23 * * 1-5","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":null,"each":true,"kind":"read","label":"Target scenarios","links":[],"target":"settings/target-scenarios.json"},{"detail":"period=max, cached for the day","each":true,"kind":"source","label":"Full price history","links":[],"target":"Yahoo Finance"},{"detail":"Accomplished when the high (or low) of the next N days reaches close \u00d7 (1 + x %)","each":true,"kind":"compute","label":"Outcome per scenario and day","links":[],"target":null},{"detail":"Per ticker and scenario: delete, then copy and merge","each":true,"kind":"write","label":"Replace in the database","links":[],"target":"PostgreSQL ai_tickerdata_altotickerscenariodailyvalue"}],"summary":"For each target scenario (a move of x % within N days), the days it was accomplished, replaced in PostgreSQL.","title":"Scenario outcomes","used_by":["data-quality"]},{"arguments":{"ticker_code":null},"group":"Scoring","items":"ticker","last_run":null,"name":"compute-indicators","part_of":["optimize-strategies"],"per_ticker":true,"runs":[{"aliases":[],"label":"Compute indicators","method":"POST","note":null,"params":["ticker"],"path":"/tickers/refresh/indicators","path_params":{},"warning":null}],"schedule":{"comment":"Heavy: about 55 min per long-history ticker today (docs/performance.md)","cron":"0 1 * * 6","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"period=max, cached for the day","each":true,"kind":"source","label":"Full price history","links":[],"target":"Yahoo Finance"},{"detail":"Indicators, their parameters and parameter values","each":true,"kind":"read","label":"Indicator settings","links":[],"target":"settings/indicator*.json"},{"detail":"Every indicator \u00d7 parameter combination (finta)","each":true,"kind":"compute","label":"Base indicators","links":[],"target":null},{"detail":"Staging table, COPY, then MERGE of the new and changed values","each":true,"kind":"write","label":"Upsert into the database","links":[],"target":"PostgreSQL ai_tickerdata_altotickerindicatordailyvalue"}],"summary":"Every base indicator \u00d7 parameter combination over the full history, upserted into PostgreSQL. Heavy: up to tens of millions of rows per ticker.","title":"Base indicators","used_by":["data-quality"]},{"arguments":{"ticker_code":null},"group":"Scoring","items":"ticker","last_run":null,"name":"optimize-strategies","part_of":[],"per_ticker":true,"runs":[{"aliases":["/tickers/refresh/optimize"],"label":"Optimise","method":"POST","note":null,"params":["ticker"],"path":"/scoring/optimize","path_params":{},"warning":null}],"schedule":{"comment":null,"cron":"0 1 * * 0","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Full price history, cached for the day","each":true,"kind":"source","label":"Download","links":[],"target":"Yahoo Finance"},{"detail":"Scenario outcomes, in memory (nothing written to the database)","each":true,"kind":"compute","label":"Scenarios","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/scenarios"},"pipeline":"compute-scenarios","relation":"same"}],"target":null},{"detail":"Base indicators in memory, then the computed ones derived from them","each":true,"kind":"compute","label":"Indicators","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/indicators"},"pipeline":"compute-indicators","relation":"same"}],"target":null},{"detail":"The backoffice's conditions evaluated day by day (non-causal Chikou excluded)","each":true,"kind":"compute","label":"Signal conditions","links":[],"target":"settings/signal-conditions.json"},{"detail":"Single conditions and AND-combinations of 2 to 5 that preceded each scenario: hit rate > 80 %, \u2265 5 episodes, binomial p \u2264 0.01","each":true,"kind":"compute","label":"Retrofit","links":[],"target":null},{"detail":"\u2265 3 years of training, 1-year test windows, costs and a 500-placebo test: validated or not","each":true,"kind":"compute","label":"Walk-forward backtest","links":[],"target":null},{"detail":"Good signal conditions and the backtest","each":true,"kind":"write","label":"Export","links":[],"target":"data/<TICKER>/05_good_signal_conditions.json, 07_backtest.json","view":{"method":"GET","params":["ticker"],"path":"/scoring/backtest"}},{"detail":"With their en/fr/es names and descriptions and their scenarios' statistics","each":true,"kind":"write","label":"Validated strategies","links":[],"target":"data/<TICKER>/06_template_strategies.json","view":{"method":"GET","params":["ticker"],"path":"/scoring/strategies"}}],"summary":"The full scoring pipeline, from the price history to each ticker's validated strategies, saved under data/<TICKER>/. Nothing is posted: sync-provider-strategies publishes the strategies.","title":"Strategy optimisation","used_by":["compute-flags","sync-provider-strategies"]},{"arguments":{"date_code":null,"sync":true,"ticker_code":null},"group":"Scoring","items":"active ticker","last_run":null,"name":"compute-flags","part_of":[],"per_ticker":true,"runs":[{"aliases":["/scoring/score","/tickers/score/technical-indicators"],"label":"Compute flags","method":"POST","note":"date: the day D (default today in Europe/Paris, never in the future)","params":["ticker","date","sync"],"path":"/tickers/refresh/signals","path_params":{},"warning":"Unless 'Post to the backoffice' is off, it replaces the alto_scoring_engine signals of the day in the backoffice: users see them in the Hub and the newsletters."}],"schedule":{"comment":"Daily flags from the validated strategies, posted as the alto_scoring_engine signals dated today: before the 08:00 'am' newsletters (Europe/Paris); every day for crypto, stocks are skipped at weekends (weekday holidays are not known yet). Off until the first exported strategies are reviewed: it publishes signals to users","cron":"15 6 * * *","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Settings refetched once older than the TTL. The day D; every active ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"None: no_strategy","each":true,"kind":"read","label":"Validated strategies","links":[{"endpoint":{"method":"POST","path":"/scoring/optimize"},"pipeline":"optimize-strategies","relation":"uses"}],"target":"data/<TICKER>/06_template_strategies.json"},{"detail":"Weekend of a market that does not trade then: market_closed","each":true,"kind":"filter","label":"Market open on D?","links":[],"target":null},{"detail":"Bypassing the day cache; only the bars before D","each":true,"kind":"source","label":"Fresh price history","links":[],"target":"Yahoo Finance"},{"detail":"No bar of the previous session (no_new_bar), or one still incomplete (incomplete_bar)","each":true,"kind":"filter","label":"Bar checks","links":[],"target":null},{"detail":"Only the base and computed indicators the strategies use","each":true,"kind":"compute","label":"Needed indicators","links":[],"target":null},{"detail":"Conditions ANDed; a flag when a strategy opens a position on the last bar","each":true,"kind":"compute","label":"Evaluate the strategies","links":[],"target":null},{"detail":"Each ticker's result and the day file","each":false,"kind":"write","label":"Save the flags","links":[],"target":"data/<TICKER>/signals.json, data/signals/<D>.json","view":{"method":"GET","params":["ticker","date"],"path":"/scoring/signals"}},{"detail":"Unless sync=false, the single ticker failed, or over half of the tickers with strategies failed","each":false,"kind":"write","label":"Post the day's signals","links":[{"endpoint":{"method":"POST","path":"/data_provider/sync/signals"},"pipeline":"sync-provider-signals","relation":"same"}],"target":"POST /api-scheduler/ticker-flags/custom-action/"}],"summary":"Each active ticker's validated strategies evaluated on its last bar before the day D: the buy and sell flags of D, saved and posted to the backoffice as the alto_scoring_engine signals.","title":"Daily flags","used_by":["sync-provider-signals","send-newsletters"]},{"arguments":{"ticker_code":null},"group":"Scoring","items":"ticker","last_run":null,"name":"financial-analysis","part_of":[],"per_ticker":true,"runs":[{"aliases":[],"label":"Analyse","method":"POST","note":null,"params":["ticker"],"path":"/tickers/score/financial-analysis","path_params":{},"warning":null}],"schedule":null,"steps":[{"detail":"Settings refetched once older than the TTL. Every ticker, or the one requested","each":false,"kind":"read","label":"Settings and tickers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/tickers.json"},{"detail":"Financials, balance sheet, cash flow, last close","each":true,"kind":"source","label":"Statements and price","links":[],"target":"Yahoo Finance"},{"detail":"EPS, P/E, P/B, ROE, ROA, EBITDA, debt/EBITDA, current ratio, FCF, growth","each":true,"kind":"compute","label":"Ratios","links":[],"target":null},{"detail":"An interpretation per ratio and a recommendation, logged","each":true,"kind":"compute","label":"Score out of 20","links":[],"target":null}],"summary":"Fundamental ratios and a score out of 20. Not stored: the result of a single-ticker run, and the logs, are the only output.","title":"Fundamental score","used_by":[]},{"arguments":{"data_provider_code":null,"per_ticker":false},"group":"Data providers","items":"data provider","last_run":null,"name":"sync-provider-strategies","part_of":[],"per_ticker":false,"runs":[{"aliases":[],"label":"Template strategies","method":"POST","note":null,"params":["data_provider"],"path":"/data_provider/sync/strategies","path_params":{},"warning":"It replaces every strategy of the provider in the backoffice."},{"aliases":[],"label":"Per-ticker strategies","method":"POST","note":null,"params":["data_provider"],"path":"/data_provider/sync/ticker-strategies","path_params":{},"warning":"It replaces every strategy of the provider in the backoffice."}],"schedule":null,"steps":[{"detail":"Every provider of settings/data-providers.json, or the one requested","each":false,"kind":"read","label":"Settings and providers","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/data-providers.json"},{"detail":"The validated strategies of every ticker, concatenated","each":true,"kind":"read","label":"alto_scoring_engine","links":[{"endpoint":{"method":"POST","path":"/scoring/optimize"},"pipeline":"optimize-strategies","relation":"uses"}],"target":"data/<TICKER>/06_template_strategies.json","view":{"method":"GET","params":[],"path":"/scoring/strategies"}},{"alternative":true,"detail":"Template strategies (per ticker: BTC-EUR only)","each":true,"kind":"source","label":"tonydee","links":[],"target":"altotrades.com"},{"detail":"The backoffice rejects an empty bulk-load","each":true,"kind":"filter","label":"No strategies, nothing posted","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Replace the provider's strategies","links":[],"target":"POST /api-scheduler/strategies/bulk-load/"}],"summary":"Each data provider's strategies bulk-loaded into the backoffice, replacing the provider's previous ones.","title":"Provider strategies","used_by":[]},{"arguments":{"data_provider_code":null,"date_code":null,"days_back":1},"group":"Data providers","items":"provider and day","last_run":{"created_at":"2026-11-15T22:00:00+00:00","error":null,"finished_at":"2026-11-15T22:00:01+00:00","id":"f5b0e6a431e843808e96fe52b1c66120","name":"sync-provider-signals","params":{"data_provider_code":null,"date_code":null,"days_back":1},"progress":{"done":2,"total":2},"started_at":"2026-11-15T22:00:00+00:00","status":"failed","summary":{"failed":1,"skipped":1,"succeeded":0,"total":2},"trigger":"schedule"},"name":"sync-provider-signals","part_of":["compute-flags"],"per_ticker":false,"runs":[{"aliases":[],"label":"Sync signals","method":"POST","note":"The days ending at date (default today); more than 1 day runs as a background job","params":["data_provider","date","days_back"],"path":"/data_provider/sync/signals","path_params":{},"warning":"It replaces the provider's signals of each day in the backoffice: users see them."}],"schedule":{"comment":"Every active data provider with a signal source (pipelines.SIGNAL_SOURCES); the others are skipped. Before Prefect: every 45 min. A cron cannot repeat every 45 min across hours: this runs at :00 and :45","cron":"*/45 * * * *","enabled":true,"next_run_at":"2026-11-15T22:45:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Active providers with a signal source (the others are listed as skipped) \u00d7 the days","each":false,"kind":"read","label":"Settings, providers and days","links":[{"endpoint":{"method":"POST","path":"/refresh/settings"},"pipeline":"refresh-settings","relation":"same"}],"target":"settings/data-providers.json"},{"detail":"Its results of the day","each":true,"kind":"source","label":"tonydee","links":[],"target":"altotrades.com"},{"alternative":true,"detail":"The flags last posted for the day, read under the day file's lock","each":true,"kind":"read","label":"alto_scoring_engine","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/signals"},"pipeline":"compute-flags","relation":"uses"}],"target":"data/signals/<day>.json","view":{"method":"GET","params":["date"],"path":"/scoring/signals"}},{"detail":"The source has no signals: skipped, nothing posted","each":true,"kind":"filter","label":"Nothing for the day yet","links":[],"target":null},{"detail":"Posted even when empty: no signal that day","each":true,"kind":"write","label":"Replace the day's signals","links":[],"target":"POST /api-scheduler/ticker-flags/custom-action/"}],"summary":"Each provider's signals of the day posted to the backoffice, replacing its signals of that day: tonydee's from altotrades.com, alto_scoring_engine's from what compute-flags last posted.","title":"Provider signals","used_by":["refresh-newsletters","send-newsletters","send-weekly-digest","data-quality"]},{"arguments":{"date_code":null,"days_back":1},"group":"Newsletters","items":"day","last_run":{"created_at":"2026-11-15T22:00:00+00:00","error":null,"finished_at":"2026-11-15T22:00:00+00:00","id":"d193ecdf23a640c681ba3e3c9a4fda07","name":"refresh-newsletters","params":{"date_code":null,"days_back":1},"progress":{"done":1,"total":1},"started_at":"2026-11-15T22:00:00+00:00","status":"succeeded","summary":{"failed":0,"skipped":0,"succeeded":1,"total":1},"trigger":"schedule"},"name":"refresh-newsletters","part_of":[],"per_ticker":false,"runs":[{"aliases":[],"label":"Today","method":"POST","note":null,"params":[],"path":"/newsletters/refresh","path_params":{},"warning":null},{"aliases":[],"label":"Date and days before","method":"POST","note":"From date \u2212 days before to date","params":["date","retro_days"],"path":"/newsletters/refresh/<date_code>/<int:retro_days>","path_params":{"date_code":"date","retro_days":"retro_days"},"warning":null}],"schedule":{"comment":"As before Prefect (every 60 min). Asks the backoffice to rebuild today's newsletter from its signals; sends no e-mail (send-newsletters does). Enabled 2026-11-14","cron":"0 * * * *","enabled":true,"next_run_at":"2026-11-15T23:00:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"The days ending at the date (default today)","each":false,"kind":"compute","label":"The days","links":[],"target":null},{"detail":"A POST with the date","each":true,"kind":"write","label":"Recompute the newsletter","links":[{"endpoint":{"method":"POST","path":"/data_provider/sync/signals"},"pipeline":"sync-provider-signals","relation":"uses"}],"target":"POST /api-scheduler/newsletters/rebuild/"},{"detail":"An HTTP error, or a status other than 200 / ok, fails the day","each":true,"kind":"filter","label":"Error status","links":[],"target":null}],"summary":"Asks the backoffice to rebuild the newsletter of each day from its signals.","title":"Newsletter recompute","used_by":["data-quality"]},{"arguments":{"ignore_send_time":false},"group":"Newsletters","items":"subscribed user","last_run":null,"name":"send-newsletters","part_of":[],"per_ticker":false,"runs":[{"aliases":[],"label":"Send the due ones","method":"POST","note":null,"params":["ignore_send_time"],"path":"/newsletters/send","path_params":{},"warning":"It emails the users whose newsletter is due now (every subscribed user with 'Ignore send time')."}],"schedule":{"comment":"Every hour: emails the subscribed users whose send time has come (their am/pm hour, in their timezone, on their weekdays) and retries the failed ones. Must run at least hourly","cron":"0 * * * *","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"notifications_active only","each":false,"kind":"read","label":"Subscribed users","links":[],"target":"GET /api-admin/users/"},{"detail":"Their send time has come today (ignore_send_time: now); valid email","each":true,"kind":"filter","label":"Due now?","links":[],"target":null},{"detail":"Created by the backoffice from the day's signals if missing","each":true,"kind":"read","label":"The user's newsletter","links":[{"endpoint":{"method":"POST","path":"/data_provider/sync/signals"},"pipeline":"sync-provider-signals","relation":"uses"},{"endpoint":{"method":"POST","path":"/tickers/refresh/signals"},"pipeline":"compute-flags","relation":"uses"}],"target":"GET /api-scheduler/user-newsletters/for-user/?username=<email>&date=<day>"},{"detail":"An empty one is marked sent if the user opted out of them","each":true,"kind":"filter","label":"Already sent, or empty","links":[],"target":null},{"detail":"Buy and sell lists, upcoming earnings within 7 days, unsubscribe link, in the user's language","each":true,"kind":"compute","label":"Build the email","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/calendar"},"pipeline":"refresh-calendar","relation":"uses"}],"target":"templates/newsletter.html","view":{"method":"GET","params":[],"path":"/newsletters/preview"}},{"detail":"Retried in the run on failure","each":true,"kind":"send","label":"Send with Brevo","links":[],"target":null},{"detail":"Only once delivered: the next hourly run retries the others","each":true,"kind":"write","label":"Mark it sent","links":[],"target":"PUT /api-admin/user-newsletters/<id>/"}],"summary":"Emails each subscribed user their newsletter at their own send time (am 08:00 or pm 18:00 in their timezone, weekdays): meant to run every hour.","title":"Daily newsletters","used_by":["data-quality"]},{"arguments":{"week_of":null},"group":"Newsletters","items":"subscribed user","last_run":null,"name":"send-weekly-digest","part_of":[],"per_ticker":false,"runs":[{"aliases":[],"label":"Send the digest","method":"POST","note":"date: in or after the week to send (default today: the last week whose Friday has come)","params":["date"],"path":"/newsletters/send-weekly","path_params":{},"warning":"It emails every subscribed user the weekly digest (those already sent it are skipped)."}],"schedule":{"comment":"Saturday recap of the week's signals, on top of the daily newsletters, to every subscribed user (no per-user choice in the backoffice yet): enable once the product decision is made","cron":"0 9 * * 6","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Monday to Friday of the last week whose Friday is on or before date","each":false,"kind":"compute","label":"The week","links":[],"target":null},{"detail":"notifications_active only","each":false,"kind":"read","label":"Subscribed users","links":[],"target":"GET /api-admin/users/"},{"detail":"Sent digests are recorded, so a re-run only sends the others","each":true,"kind":"filter","label":"Already sent, invalid email","links":[],"target":"data/runs.sqlite3 (deliveries)"},{"detail":"The user's five daily newsletters","each":true,"kind":"read","label":"The week's newsletters","links":[{"endpoint":{"method":"POST","path":"/data_provider/sync/signals"},"pipeline":"sync-provider-signals","relation":"uses"}],"target":"GET /api-scheduler/user-newsletters/for-user/?username=<email>&date=<day>"},{"detail":"No flag and the user opted out of empty newsletters: recorded, not sent","each":true,"kind":"filter","label":"Empty","links":[],"target":null},{"detail":"One line per ticker and signal type, most flagged first","each":true,"kind":"compute","label":"Build the digest","links":[],"target":null,"view":{"method":"GET","params":[],"path":"/newsletters/preview/weekly"}},{"detail":"As the daily newsletters","each":true,"kind":"send","label":"Send with Brevo","links":[],"target":null},{"detail":null,"each":true,"kind":"write","label":"Record the delivery","links":[],"target":"data/runs.sqlite3 (deliveries)"}],"summary":"Emails every subscribed user the recap of a Monday-to-Friday week: each ticker and signal type with the weekdays it was flagged.","title":"Weekly digest","used_by":[]},{"arguments":{},"group":"Maintenance","items":"family of checks","last_run":null,"name":"data-quality","part_of":[],"per_ticker":false,"runs":[{"aliases":[],"label":"Run the checks","method":"POST","note":null,"params":[],"path":"/refresh/data-quality","path_params":{},"warning":null}],"schedule":{"comment":null,"cron":"0 9 * * *","enabled":false,"next_run_at":null,"params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Active tickers, and when a check needs them markets, holidays, countries, currencies, sectors, industries, plans, indicators, strategies, users\u2026","each":false,"kind":"read","label":"Tickers and reference lists","links":[],"target":"GET /api-admin/\u2026"},{"detail":"Latest, invalid and stale prices; key info, analysts, sectors and industries","each":true,"kind":"read","label":"Ticker prices and profile","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/price"},"pipeline":"refresh-prices","relation":"uses"},{"endpoint":{"method":"POST","path":"/tickers/refresh/information"},"pipeline":"refresh-information","relation":"uses"}],"target":"PostgreSQL (read-only)"},{"detail":"Gaps, duplicates and anomalies of the daily prices","each":true,"kind":"read","label":"Price history","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/price-history"},"pipeline":"refresh-price-history","relation":"uses"}],"target":"ai_tickerdata_altotickerdailyprice"},{"detail":null,"each":true,"kind":"read","label":"News, financials, dividends","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/news-sentiment"},"pipeline":"refresh-news","relation":"uses"},{"endpoint":{"method":"POST","path":"/tickers/refresh/financial-information"},"pipeline":"refresh-financials","relation":"uses"},{"endpoint":{"method":"POST","path":"/tickers/refresh/dividends"},"pipeline":"refresh-dividends","relation":"uses"}],"target":"PostgreSQL (read-only)"},{"detail":"Missing and stale rows","each":true,"kind":"read","label":"Scenarios and indicators","links":[{"endpoint":{"method":"POST","path":"/tickers/refresh/scenarios"},"pipeline":"compute-scenarios","relation":"uses"},{"endpoint":{"method":"POST","path":"/tickers/refresh/indicators"},"pipeline":"compute-indicators","relation":"uses"}],"target":"PostgreSQL (read-only)"},{"detail":"Providers without recent data, signals without a price","each":true,"kind":"read","label":"Provider signals","links":[{"endpoint":{"method":"POST","path":"/data_provider/sync/signals"},"pipeline":"sync-provider-signals","relation":"uses"}],"target":null},{"detail":"Generated and sent on time","each":true,"kind":"read","label":"Newsletters","links":[{"endpoint":{"method":"POST","path":"/newsletters/refresh"},"pipeline":"refresh-newsletters","relation":"uses"},{"endpoint":{"method":"POST","path":"/newsletters/send"},"pipeline":"send-newsletters","relation":"uses"}],"target":null},{"detail":"Countries, currencies and exchange rates, markets, indices","each":true,"kind":"read","label":"Reference data","links":[],"target":null},{"detail":"Market sessions and holidays, plan titles, indicator texts and parameters, strategy descriptions, accounts differing by case, sign-ups never activated (syntax, MX, disposable, typo). One line per problem, nothing is changed","each":true,"kind":"compute","label":"Admin-team controls","links":[],"target":null},{"detail":"A check that crashed is reported with its error; new and fixed findings against the previous report","each":false,"kind":"write","label":"Save the report","links":[],"target":"data/data_quality/data_quality_verifications.json","view":{"method":"GET","params":[],"path":"/get/data-quality"}},{"detail":"The same report in Markdown: summary table, then one line per problem","each":false,"kind":"write","label":"Admin-team report","links":[],"target":"data/data_quality/data_quality_report.md","view":{"method":"GET","params":[],"path":"/get/data-quality/report"}}],"summary":"58 checks of the data the other pipelines produce and of the reference and content data the admin team maintains (PIPE-12), each with the number of objects in error, the corrective action and what changed since the previous run, saved as a report.","title":"Data quality checks","used_by":[]},{"arguments":{"days":null},"group":"Maintenance","items":"backoffice call","last_run":{"created_at":"2026-11-15T03:20:00+00:00","error":null,"finished_at":"2026-11-15T03:20:00+00:00","id":"b0fc329e42d94b9b956a58bee03ae44a","name":"purge-email-events","params":{"days":null},"progress":null,"started_at":"2026-11-15T03:20:00+00:00","status":"succeeded","trigger":"schedule"},"name":"purge-email-events","part_of":[],"per_ticker":false,"runs":[{"aliases":[],"label":"Purge old events","method":"POST","note":"Optional ?days=n keeps the last n days instead of the backend's EMAIL_EVENT_RETENTION_DAYS","params":[],"path":"/emails/purge-events","path_params":{},"warning":null}],"schedule":{"comment":"PIPE-31: deletes the backoffice's raw Brevo webhook events older than its EMAIL_EVENT_RETENTION_DAYS (180). Daily, idempotent, any time of day. Enabled 2026-11-14; the route exists from the backend deploy that ships FEAT-85","cron":"20 4 * * *","enabled":true,"next_run_at":"2026-11-16T03:20:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Answers the number deleted and the retention applied; idempotent","each":false,"kind":"write","label":"Delete the old events","links":[],"target":"POST /api-scheduler/emails/purge-events/"}],"summary":"Asks the backoffice to delete the raw Brevo delivery events (delivered, opens, clicks, bounces\u2026) older than its retention, 180 days by default (PIPE-31). Each e-mail's row and counters stay.","title":"E-mail events purge","used_by":[]},{"arguments":{},"group":"Maintenance","items":"settings file","last_run":{"created_at":"2026-11-15T04:00:00+00:00","error":null,"finished_at":"2026-11-15T04:00:01+00:00","id":"bf7945fd88a942d0be0d26fccf5d4787","name":"refresh-settings","params":{},"progress":null,"started_at":"2026-11-15T04:00:00+00:00","status":"succeeded","trigger":"schedule"},"name":"refresh-settings","part_of":["refresh-prices","refresh-information","refresh-price-history","refresh-news","rescore-news-sentiment","refresh-financials","refresh-analyst-ratings","refresh-dividends","refresh-calendar","refresh-sector-industry","compute-scenarios","compute-indicators","optimize-strategies","compute-flags","financial-analysis","sync-provider-strategies","sync-provider-signals"],"per_ticker":false,"runs":[{"aliases":[],"label":"Refresh settings","method":"POST","note":null,"params":[],"path":"/refresh/settings","path_params":{},"warning":null}],"schedule":{"comment":"Forced refetch of settings/*.json; the pipelines also refetch them when older than SETTINGS_TTL_SECONDS","cron":"0 5 * * *","enabled":true,"next_run_at":"2026-11-16T04:00:00+00:00","params":{},"timezone":"Europe/Paris"},"steps":[{"detail":"Tickers, markets, data providers, indicators and their parameters, scenarios, signal conditions","each":true,"kind":"read","label":"Fetch from the backoffice","links":[],"target":"GET /api-admin/\u2026"},{"detail":null,"each":true,"kind":"write","label":"Save atomically","links":[],"target":"settings/*.json"}],"summary":"Every settings file fetched again from the backoffice, ignoring the TTL. The other pipelines do the same when the files are older than SETTINGS_TTL_SECONDS.","title":"Settings","used_by":[]}],"scheduler":{"error":null,"last_seen_at":"2026-11-15T22:10:00+00:00","running":true}}
