Как устроен TakeProfit — целиком
Реверс терминала по полному графу кода + живой захват: архитектура, все виджеты, чарт-движок, данные, платформа, мобилка и дизайн — с verbatim-кодом и скринами.
Архитектура
TakeProfit — браузерный торговый терминал на единой WebGL-сцене. График, стакан и пузыри — это GPU/Canvas-движки; данные идут бинарным Protobuf через стрим-воркеры; рабочее пространство — докинг-сетка.
Главный приём: весь workspace рисуется в один WebGL2-canvas на весь вьюпорт (как игровой движок), поверх — DOM-оверлеи виджетов (<section class="widget">) в докинг-сетке Lumino. Рендер on-demand — 0 draw-call в покое, замерено.
Проверено по полному графу: весь код — 352 JS-чанка / 12 МБ (замыкание импортов завершено) + 6 стрим-воркеров + 46 CSS. Во всём графе 0 ссылок на .wasm и нет WebAssembly.instantiate для расчётов → клиентского WASM нет; «WASM C/C++» из маркетинга — серверный рантайм Indie (R_WASM) либо преувеличение.
Технологический стек
Полный список библиотек, идентифицированных по сигнатурам (version-строки вырезаны минификатором). high
| Слой | Технология |
|---|---|
| Каркас | SvelteKit + Svelte 5 (runes) |
| График — модель/ввод | TradingView Lightweight Charts (форк) |
| График — рендер | PixiJS v7 · WebGL2 (instancing, GLSL) |
| Виджеты/докинг | Lumino (@lumino/widgets + @lumino/dragdrop) |
| RPC/данные | Connect-Web (@connectrpc) + protobuf-es (@bufbuild) |
| Воркеры/стримы | Comlink RPC в SharedWorker |
| HTTP-клиент | ky (REST: /api/*) |
| Server-state кэш | TanStack Query |
| Стакан/пузыри | собственный TxOrderBook на Canvas 2D |
| Скрипт-редактор | CodeMirror 6 + грамматика Lezer-Python |
| Подсветка кода (доки) | highlight.js |
| Notes/Feed редактор | собственный block-tree (не ProseMirror/Tiptap) |
| Хоткеи | tinykeys + Lumino CommandRegistry |
| i18n | Paraglide JS (inlang), только en + нативный Intl |
| Валидация схем | Yup |
| Биллинг | Stripe.js v3 + svelte-stripe-js |
| Аналитика | PostHog 1.376.0 (self-proxy) + Sentry + GA4 + Reddit pixel |
| Согласие cookie | Termly |
| Auth | Stytch (Google OAuth) + cookie-сессия |
| Эмодзи | PicMo; даты — dayjs |
Система виджетов (Lumino)
Мозаика виджетов на Lumino DockPanel (быв. PhosphorJS) под кастомным LayoutManager. high
- Дерево = нативный Lumino-конфиг:
split-area(orientation,sizes— доли, children) +tab-area(widgets[{ID}], currentIndex). - Drop-зоны (
findDropTarget): порогиDEFAULT_EDGES={top:12,right:40,bottom:40,left:40}px; центр виджета = вкладка, иначе ближайшая грань. - Оверлей: root-зоны занимают 0.618 (золотое сечение) высоты/ширины; скрытие
overlay.hide(100). - Resize (
BoxEngine.adjust): zero-sum между соседями с min/max; spacing 4px. - Табы: drag при ≥5px, отрыв (tear-off) за contentRect±20px.
- На мобиле → single-document mode (один виджет, табы скрыты).
DEFAULT_EDGES={top:12,right:40,bottom:40,left:40}Px-пороги root-зон drop.
case"root-top":...l=h.height*F.GOLDEN_RATIO;break;Оверлей root-top = 0.618 высоты.
s.DRAG_THRESHOLD=5,s.DETACH_THRESHOLD=20TabBar: старт drag 5px, отрыв ±20px.
Каталог виджетов
Хаб «Add Widgets» (drawer с превью). Все типы: high
| Виджет | Логика / источник |
|---|---|
| Chart | LWC-модель + Pixi/WebGL2; свечи/бары/линия/area/baseline, индикаторы в пейнах, рисование, crosshair |
| Watchlist | Svelte-store + localStorage; live QuoteApi/QuoteStream; builtIn + userDefined листы |
| Screener | StockScreenerApi/Search + категории; фильтры/сортировка |
| Financials | FundamentalApi (P/E, P/S, EV/EBITDA…), периоды Yr/QTR |
| Market Depth | стакан + Order Flow Bubbles, Canvas2D «TxOrderBook» |
| Indie® Code Editor | CodeMirror 6, DSL Indie, серверная компиляция |
| Strategy/Backtesting | server-driven отчёт (StrategyReportStylistApi), equity/drawdown |
| Feed | лента комьюнити (TanStack Query + api/posts) |
| Notes | block-tree редактор; заметки по бумаге (api/publications/note) |
| Account | торговый счёт брокера (equity/PnL/margin), ключи бирж |
| Lime / J2T / Ilotcos | брокерские order/portfolio — iframe (бэкенд Finam; J2T=MT5) |
Watchlist · Feed · Notes
Watchlist high
- Svelte-store + персист в localStorage с версией; два типа листов:
builtIn(read-only пресеты) иuserDefined. - Live-котировки:
loadSecurityInfos→ per-security quote-stores (дедуп по streamerID), поля last/bid/ask/open/high/low/volume/change/%. - Виртуализация таблицы, ресайз колонок в %, flash изменения цены (both/absolute/percent).
Feed (комьюнити) high
- TanStack Query (infinite, постраничная) + ky REST
api/posts(CRUD, like/unlike). - Сортировки: Popular/Recent/Most commented. Тело поста — тот же block-tree редактор;
paid= монетизация. - SvelteKit-роуты
/feed,/feed/[tag]/page-[n].
Notes — block-tree редактор high
- Полностью кастомный block-tree движок (НЕ ProseMirror/Tiptap/Lexical/Editor.js):
core.{model,builder,selection,render,node,time,normalizer,plugins,autocomplete}. - Модель: дерево
{type,attributes,body[]}; Section→Container→Widget/Text; DOM-биндинг через[data-node-id]. - Inline-марки bold/italic/underline/strike/link; списки numerable/marker; slash-меню; undo/redo (
core.time). - Заметки привязаны к
securityID, сохраняются RESTapi/publications/note.
const e=t.closest("[data-node-id]"),i=e?this.core.render.getNodeById(e.dataset.nodeId):this.core.model;DOM-узел ↔ модель по data-node-id.
getNextPageParam:r=>r.pagination.currentPage<r.pagination.totalPageAmount?...+1:nullFeed: постраничная инфинит-пагинация (TanStack Query).
Рендереры серий + скейлы
Форк Lightweight Charts (модель/оси/crosshair) + кастомный PixiJS v7 / WebGL2 рендерер. Каждая серия — свой GLSL-шейдер. high
- Свечи — instanced: stride 17 float (68 байт) (time+OHLC+body/border/wick) или 9 float; тело/фитиль во фрагментном шейдере, субпиксельный AA.
uWidth=.6. - Бары — 9 float; гистограмма — 7 float (28 байт); линия/area/baseline — polyline (расширение сегментов).
- Y инвертирован (отрицательные OHLC), premultiplied alpha, гарантированная мин-высота дожи.
- 4 прайс-скейла в GLSL: NORMAL/LOG/PERCENT/INDEXED. Лог:
0.4342944819·log(|p|+off). - GPU-picking: второй проход рендерит серию уникальным
uidColor. - Crosshair magnet: дефолт magnet,
magnetThreshold:16px, weakMagnet притягивает к OHLC в пределах порога.
e[r+n++]=i.time,e[r+n++]=-i.open,e[r+n++]=-i.high,...,e[r+n++]=i.color.r/255setBarData: OHLC отрицательные (экран Y вниз).
#define SCALE_NORMAL 0 SCALE_LOG 1 SCALE_PERCENT 2 SCALE_INDEXED 34 режима скейла в вершинном шейдере.
Pan/Zoom · анимации · рендер
Pan / Zoom high
- Wheel-зум:
deltaY/100, deltaMode ×120/×32,zoomTimeякорь к курсору; barSpacing 10%/ед.; скроллscrollChart(-80·t). - Drag-pan: navigate после порога 20px. Инерция (kinetic) только touch:
KineticAnimation(.2,7,.997,15), эксп. затухание. - Анимаций видимого диапазона нет изинга (
setVisibleRange/fitContentмгновенны). barSpacing: min .5 … 0.5·width, дефолт 6.
Анимации (3 слоя) high
- PixiJS Ticker (рендер) + kinetic (инерция) + Svelte 5 transitions (fly/fade/slide, 400мс, cubicInOut).
- Корректировка: «
ease*»-семьи нет — это подстрокиincrease/release. Spring/cubic-bezier нет.
On-demand рендер high
- Автотикер Pixi выключен; свой rAF зовёт
ticker.update()только еслиscenes.some(isNeedRedraw()). - Dirty-флаги consume-on-read; в покое 0 draw-call, rAF на 120Гц.
r.ticker.autoStart=!1,r.ticker.stop();const n=()=>{r?.scenes.some(a=>a.isNeedRedraw())&&r.ticker.update(),requestAnimationFrame(n)}On-demand рендер.
getPosition(e){...return t.position+speed*(Math.pow(dumping,i)-1)/Math.log(dumping)}Kinetic-инерция: эксп. затухание.
Настройки графика + сравнение
Декларативная панель настроек (контролы как объекты), схемы на Yup. 5 групп. high
- Style: тип Candles/Line/Bars; цвета свечей body/border/wicks + volume (дефолты из
--colors-chart-*). - Canvas: фон, текст, Grid (none/hor/vert/hor&vert), Crosshair (solid/dashed/dotted).
- Security Label: внутричартовый watermark (Logo/Name/Exchange/Status + OHLC).
- Scales: тип (Regular/Logarithmic/Percent/Index to 100), price labels, Timezone (дефолт Etc/UTC), Extended Hours.
- Alerts: настройки алертов на графике.
- Шаблоны Chart Settings (save/reuse: запоминают тип графика + extended sessions). У индикаторов шаблонов нет.
- Extended Hours: session-типы PRE_MARKET/MAINSESSION/POST_MARKET; запрос данных меняет набор сессий; tradeState HALTED.
- Per-instance индикаторы: protobuf-oneof параметры (bool/string/timeFrame/source/color/historyRange) + output-стили (line/marker/fill/background/barColor/histogram/columns/steps).
- Сравнение символов (VS): мульти-security, вторичные = bar-series в подвале; палитра 8 цветов; % через Scale Type Percent/Index-to-100.
hse={normal:"Regular",logarithmic:"Logarithmic",percentage:"Percent",indexedTo100:"Index to 100"}Режимы скейла → LWC PriceScaleMode.
aD=["#B578FD","#FFEA2E","#60A5FA","#BBE319","#FB7185","#2EB844","#FF773D","#A3A3A3"]Палитра серий сравнения (8 цветов).
showExtendedSessions?[PRE_MARKET,MAINSESSION,POST_MARKET]:[MAINSESSION]Extended Hours = набор session-типов в запросе.
Инструменты рисования + слои
Проприетарный слой поверх LWC, рендер — Pixi. Точки в логических координатах {time, indexOffset, price}. high
- 7 групп тулбара: Measures/Positions (Long&Short, Date&Price, Volume Profile), Lines (Line/Arrow/Ray/TrendAngle/H/V/Cross/Channel), Patterns (XABCD/Cypher/H&S/ABCD/Triangle/3Drives/Elliott), Shapes (Circle/Rect/Triangle/Ellipse/Curve/Arc), Drawings (Pen/Highlighter/Path/Polygon), Fibonacci (Retracement/Extension/Fan/TimeZone), Texts (Text/Callout/PriceTag). Pitchfork/Gann — нет.
- Магнит: 3 режима,
magnetThreshold:16px, snap к OHLC; snap-to-angle к 45°. - Object Tree (слои): pane/drawing/folder/indicator/symbol; папки, DnD, видимость, блокировка, z-order.
- Персистентность по 4 областям: global / workspace / channel / local (рисунки на индикаторах → local).
const mm={time:NaN,indexOffset:0,price:NaN}Точка = логическая координата.
getDrawingStoreBySyncSetting(t){return t==="global"?#t:t==="workspace"?#e:t==="channel"?#s:#r}4-уровневая персистентность (вкл. per-channel).
Indie® DSL + индикаторы
Python-подобный DSL. Редактор — CodeMirror 6 + Lezer-Python. Компиляция/исполнение — на сервере; на клиенте только парсинг/линт/автокомплит. lang_version=5. high
- stdlib: 110 типов, 291 метод, 135 полей, 32 функции, 22 декоратора, 18 enum.
- indie.algorithms (~46): Sma/Ema/Wma/Rma/Macd/Rsi/Bb/Atr/Adx/Cci/Stoch/Sar/Supertrend/Vwap/Donchian/ZigZag/Uo/Tsi/Roc/StdDev/LinReg/Corr/Percentile/Median/Highest/Lowest/PivotHighLow/Mfi/Mfv/NetVolume/CumSum/Change…
- indie.strategies: Trading(place/amend/cancel_order), Order/Position/Stop/Commission; indie.plot: Line/Histogram/Columns/Steps/Fill/Background/BarColor/Marker; indie.math: cross/cross_over/cross_under…
- Исполнение:
GetIndicatorStream(ServerStreaming) несётindicator_source_code+runtime; enumRuntime={R_PYTHON, R_WASM}, выбор AUTO/ROA_*. Миграция версий —CodeMigratorApi. - Привязка к графику:
SeriesDrawItem(oneof: line/fill/histogram/columns/marker/background/bar_color) = 1:1 сindie.plot.*. «Loading…» = ожидание первого snapshot. - Маркетплейс: репозиторий TPI («Explore Indicators»/«Community»/«My Scripts»).
Es=`# indie:lang_version = 5\nfrom indie import indicator\n@indicator('My Indie 1', overlay_main_pane=True)\ndef Main(self):\n return self.close[0]`Дефолтный шаблон индикатора.
makeEnum("...indicator.v2.Runtime",[{no:1,name:"R_PYTHON"},{no:2,name:"R_WASM"}])Серверный исполнитель: Python или WASM.
Бэктест / отчёт стратегии
Отчёт строится сервером, server-driven layout (StrategyReportStylistApi); клиент только форматирует и красит. high
- Дерево лейаута:
SummaryPanel{{boxes}}+Table→Section→Row→Cell. Ячейка несёт только стиль (metric_name, color, unit), значение — lookup по имени вmetrics[]снапшота. - Цвет: NEUTRAL→primary, GOOD→rise, BAD→fall, SIGN_DEPENDENT→знак. Unit: NUMBER/CURRENCY/PERCENT/DAY.
- Метрики: initial_capital, realized_pnl, max_equity_drawdown_%, sharpe/sortino/calmar, win_rate, profit_factor, expectancy, risk_reward, max win/loss streak, exposure, commission… (десятки полей).
- Lookback: 5000 баров Free / 20000 All-In (
count:-Ac(premiumAccess)). Guard выгрузки истории — 15000 строк. - Equity & Drawdown — встроенный индикатор (
$equity&drawdown), drawdown на левой шкале. Realtime: StrategyEvent (ORDER_SUBMITTED/FILLED/CANCELED). - Date-range Calendar (двойной picker) для границ бэктеста.
const Nc=5e3,Oc=2e4;function Ac(i){return i?Oc:Nc} // count:-Ac(premiumAccess)Lookback: 5000 Free / 20000 All-In.
[ee.GOOD]:()=>"tw-text-text-rise",[ee.BAD]:()=>"tw-text-text-fall",[ee.SIGN_DEPENDENT]:i=>i<0?...fall:...riseЦвет ячейки по enum + знаку.
Market Depth + Order Flow Bubbles
Собственный движок «TxOrderBook» на чистом Canvas 2D (НЕ Pixi): 5 наложенных canvas-слоёв с DPR-масштабом. high
- Данные: gRPC-стрим
OrderBookApi/GetOrderBookStreamв Web Worker; snapshot/delta merge (bids desc/asks asc, vol=0⇒remove). - Агрегация в ценовые корзины (levelStep, пресеты x1…x100), кумулятив, volRatio.
- Order Flow Bubbles («impulses»): сделки склеиваются при разрыве ≤
tradeAggregation=300мс; радиус = lerp(halfRow, 3·halfRow) по нормировке объёма на 95-й перцентиль. - Режимы: tradeView bar/bubble (дефолт bar), classic/pro, footprint-кластеры (5 мин). Цвета buy
#1D9169/ sell#E84144.
getOrderBookStream:{name:"GetOrderBookStream",kind:at.ServerStreaming}Источник DOM — серверный gRPC-стрим.
i.arc(b,d,m+u,0,2*Math.PI),i.fill(),i.arc(b,d,m,0,2*Math.PI),i.fill()Пузырь = два Canvas2D arc() (outline+fill).
Connect / Protobuf API
Connect-Web + protobuf-es, два протокола: gRPC-web (market-data) и Connect (trading), бинарный формат. ★ = server-streaming. high
| Service (takeprofit.*) | Методы |
|---|---|
| quote.v1.QuoteApi | QuoteStream ★, ListQuotes |
| candle.v1.CandleOffsetApi / ExtrapolationApi | QueryCandleOffsets / ListBars, GetBarTimestamp, GetBarsCount, ListOffsets |
| candle.v1.CandleStream (worker) | CandleStream ★, CandleHistoryStream ★, GetCandleOffsets, ListCandles |
| trade.v1.TradeStreamExternalApi | GetTradeStream ★ |
| order_book.v1.OrderBookApi | GetOrderBookStream ★ |
| indicator.controller.v2.ControllerApi | GetIndicatorStream ★, GetIndicatorHistory, GetIndicatorsInfo, GetStrategyOrdersAndTradesHistory |
| indicator.code_migrator.v1 | MigrateCode |
| indicator.strategy_report_stylist.v1 | GetStrategyReportLayout |
| trading.trading.v1.TradingApi | PlaceOrder, CancelOrder, UpdateOrder, GetEventsStream ★, GetPlaceOrderDataStream ★, StoreApiKey/…, SetLeverage/MarginMode/PositionMode, ListAdaptors |
| alerts.tpi_alerts.v1.AlertsApi | Create/Get/Update/Delete/Start/Stop/ListAlerts, GetUserAlertLog, Mark/DeleteAlertLogs |
| alerts.tpi_notifications.v1 | TestUserWebhook |
| alerts.tpi_popup_sender.v1 | SendUserNotification, GetUserNotificationStream ★ |
| reference.external.{exchange,industry,security} | ListExchanges/ListAliases, GetIndustriesTree, ListSecurities |
| screener.external.v1.SearcherApi / v2 | Search, SearchWithGroups, ListProperties/Categories; StockScreenerApi/Search |
| fundamental.v2 / ratio.v2 | GetFundamentalCatalogue, ListFundamentals / GetRatioCatalogue |
| telegram_connector.v1 | GenerateAuthLink, CheckUserAuth, Disconnect, SendMessage |
Транспорт и авторизация
- Эндпоинты: market-data
backend.takeprofit.com(/market-data/), tradingtrading.takeprofit.com(/market-data-trading/); env local/dev/stage/prod. - Auth-интерсептор: trading →
authorization: Bearer <accessToken>, market-data → сыройaccessToken. 401 → авто-refresh. - Свечи на график идут через
ControllerApi/GetIndicatorStream(основная серия = «индикатор»); лёгкийBar{{time,o,h,l,c,volume}}(double).Candle— decimal-обёртки + buying/selling split + tick_count.
Protobuf-сообщения (ключевые)
Поля ключевых сообщений (no:name:type), извлечённые из makeMessageType. high
- Candle: time(1), open/high/low/close(2-5, decimal-обёртка), value(6), volume(7), session_type(8 enum), buying/selling_value+volume(9-12), index(13), tick_count(14), day_seq_no(15).
- Bar (лёгкий, на чарт): time, open, high, low, close, volume (double).
- Quote.QuoteData: last, last_dir, last_change(+%), last_time, open/high/low, prev_close, last_volume/value, volume, value.
- OrderBookLevel: price, size. Snapshot/Update: timestamp, asks[], bids[], version(uint64).
- SecurityId: oneof spec → ticker_code(2) / isin_code(4) / guid(17).
- PlaceOrderRequest: idempotency_token, api_key_name, security_id, order, label.
- Enum: OrderType{MARKET,LIMIT}, TimeInForce{GTC,IOC,FOK}, MarginMode{cross,isolated,portfolio}, TriggerBy{LAST,MARK}, Runtime{R_PYTHON,R_WASM}, SessionType{PRE/MAIN/POST}.
Стрим-воркеры (reconnect)
Все 6 — SharedWorker (fallback DedicatedWorker) + Comlink RPC; Connect server-streaming client крутится внутри воркера. high
| Worker | Стримит |
|---|---|
| CandleStreamManager | CandleStream / CandleHistoryStream (gRPC-web) |
| TradesStreamManager | GetTradeStream |
| OrderBookStreamManager | GetOrderBookStream |
| GrpcIndieStreamManager | GetIndicatorStream (профиль ∞/1s/exp) |
| TradingStreamWorker | GetEventsStream, GetPlaceOrderDataStream + StoreApiKey (Connect) |
| PlaceOrderDataStreamManager | GetEventsStream, GetPlaceOrderDataStream + ListAdaptors (Connect) |
- Reconnect: общий цикл с тройным бэкоффом + full jitter
[s, 3s), кап 60с. Три профиля: default 10 попыток/500мс; network-lost ∞/2с (фикс); indicator ∞/1с/exp. - App-level ping/heartbeat НЕТ — живость держит fetch server-streaming + reconnect; offline-aware (ждёт
onlineevent). - Auth в воркере:
GET api/auth/token(cookie) → accessToken; gating через held-promise перед каждым запросом; refresh дедуплицирован. - Orderbook snapshot(pushMany)/delta(pushOne); свечи SERIES_LAST/SERIES_HISTORY; trades cap 1000; GC стрима через 30с после отписки.
ZP=(t,e)=>Math.max(Math.random()*(e-t)+t,t) // full jitter [s,3s); maxDelayMs=60000Reconnect: тройной бэкофф с джиттером, кап 60с.
AT={maxAttempts:10,initialDelayMs:500,exponentialBackoff:!0,maxDelayMs:6e4}Профиль reconnect по умолчанию.
Алерты
3 gRPC-сервиса, серверное вычисление условий, клиент конструирует payload и слушает поток попапов. high
- 13 типов условий: moving_up/down(+percents), cross/cross_up/down, greater/lower, entering/exiting/inside/outside_channel, multi_condition (составные).
- Операнды: цена инструмента ИЛИ значение индикатора; можно кроссить две серии. Channel-условия с upper/lower bound.
- Frequency (6): ONLY_ONCE (дефолт), ONCE_PER_BAR, ONCE_PER_BAR_CLOSE, ONCE_PER_MINUTE, ON_EVERY_TRIGGER.
- Каналы: popup, email, webhook, telegram (Discord — через webhook). Дефолт: popup+email вкл.
message_templateс переменными. - Telegram — привязка на уровне аккаунта (одноразовая ссылка с TTL). Webhook-тест отдельным методом.
- Realtime попапы:
PopupSenderApi/GetUserNotificationStream(server-stream, keepalive|alert_update). State: ACTIVE/STOPPED_*/FIRED/ERROR/EXPIRED. - Рендер на графике: geometry «Alert» (линия/канал), drag меняет порог. Срок жизни завязан на premiumAccess.
makeEnum("Condition.Frequency",[{ONLY_ONCE},{ONCE_PER_BAR},{ONCE_PER_BAR_CLOSE},{ONCE_PER_MINUTE},{ON_EVERY_TRIGGER}])6 режимов частоты, дефолт ONLY_ONCE.
NotificationChannel: popup|email|webhook|telegram (Discord = webhook URL)4 канала доставки.
Трейдинг и ордера
Нативный тикет = Connect-RPC TradingApi; брокеры Lime/J2T/Ilotcos — iframe (Finam). Trading в Beta, только Bybit. high
- Типы: MARKET/LIMIT (+stop как флаг). TIF: GTC/IOC/FOK. Маржа cross/isolated/portfolio, позиция ONE_WAY/HEDGE, TP/SL, reduceOnly, идемпотентность UUID.
- Размер/риск: quantity, % balance, % buying power, pnl; risk-based entry (SL задаёт объём). Балансы из
GetPlaceOrderDataStream. - Комиссии (дефолты Bybit): maker 0.02% / taker 0.055%. Адаптеры bybit (live) / bybit_testnet (paper).
- Брокер-iframe: postMessage-мост (requestInitData/securityChange/widgetUpdate/channelUpdate); URL
lime.widget.takeprofit.com/order/index.html. - Beta-ограничения (доки): только деривативы, только One-Way, нет Stop Market/Limit, нет редактирования ордеров.
{idempotencyToken:crypto.randomUUID(),order:{order:{case:"baseOrder",value:{side,quantity,orderType,stop,takeProfit,stopLoss,reduceOnly}}}}PlaceOrder (oneof baseOrder).
takerFeeRate:55e-5,makerFeeRate:2e-4Дефолтные комиссии (Bybit).
Авторизация (Stytch)
Stytch (self-hosted api.stytch.takeprofit.com) для OAuth + бэкенд /api/auth/*; HTTP — ky. high
- Stytch public token (prod)
public-token-live-7c58…e28f. Проводной только Google OAuth (popup). Apple/SMS/OTP/magic-link — нет. Bybit OAuth — привязка биржи. - Основной метод — email/password (+MFA
/api/auth/mfa/verify). - Сессия — HTTP-only cookie
token(credentials:"include"). RefreshGET /api/auth/token→ accessToken → в gRPC/Connect-заголовки; 401 авто-refresh. - localStorage только хинты (last_email/username/signin_method). Реферралка — Rewardful.
const r=await ci.get("api/auth/token",{credentials:"include"});return i.data.accessTokenRefresh: cookie-сессия → accessToken.
Сохранение workspace
Раскладка и настройки — на сервере (REST /api/settings через ky), не в браузере. high
- Снимок дерева (workspaces/watchlists/screeners/indicators/drawings/settings/…) + userID + version.
- Автосейв реактивный: throttled (lodash, не чаще 1/5с) + flush на beforeunload.
- 7 ky-сервисов на
/api/settings(retry:3); контракт POST/PUT/GET/DELETE с?settingType=; dirty-check. - Версии схемы для миграций (DASHBOARD_CTX:4, DRAWING_MANAGER:11, CHART_DATA:10…). Dev-инструмент
window.injectSave(). - localStorage в проде — только алерты/onboarding/тема; IndexedDB — только эмодзи-пикер.
saveDataTreeThrottled=NL(this.saveDataTree,5000)Throttle сохранения — раз в 5с.
hh.extend({prefixUrl:"/api/settings",retry:3})REST-бэкенд настроек на ky.
Поиск · хоткеи · i18n
Поиск high
- Глобальный поиск инструментов через
SearcherApi(gRPC); по TICKER+EXCHANGE_CODE, группировка (SearchWithGroups), лимит 25. Отдельно — маркетплейс индикаторов и find-in-editor (CodeMirror).
Хоткеи — tinykeys high
- Все биндинги конфигурируемы (Yup-схема
{hotkey, enabled}), persisted. Группы global/widget/search + Lumino CommandRegistry для фреймворка. - Примеры: Tab/Shift+Tab (виджеты), Shift+F (fullscreen), Alt+A (alert), $mod+Z/Shift+Z (undo/redo), $mod+C/V (copy/paste drawing), Alt+T (trend line), Alt+F (fib).
i18n — Paraglide JS high
- Paraglide JS (inlang), compile-time: каждая строка — message-функция. Доступна только локаль
en(инфраструктура мультиязычная, переводов нет). Числа/даты — нативныйIntl.*.
Yt=s=>Re({hotkey:_e().nullable().default(s),enabled:Le().default(!0)})Каждый хоткей переопределяем/отключаем (Yup).
const _="en",w=["en"] // Paraglide baseLocale/availableLocalesi18n: только английский.
Подписки и биллинг
Тарифы Free / All-In; биллинг — Stripe; фичефлаги — PostHog (remote). high
- Доступ:
session.plan==="paid"⇒ premiumAccess. 30-дневный триал All-In без карты (trialPeriodDays из metadata), one-time. - Лимиты Free vs All-In: 5000 vs 20000 свечей бэктеста; 400 cloud-алертов, unlimited workspaces, Custom Timeframes, Indie-скрипты, бэктест — All-In.
- Stripe: Stripe.js v3 + svelte-stripe-js (Elements),
confirmCardPayment(clientSecret), подписки monthly. Эндпоинтыapi/subs-platform/*. - Маркетплейс (отдельный пейволл): подписки на продукты продавцов, продавцы через Stripe Connect (
api/marketplace/*). - Фичефлаг
paywall-for-new-users(test/control) → экспериментальный план.
premiumAccess:t.data.session?.plan==="paid"paid == доступ All-In.
const r=(e,d=!0)=>a.getFeatureFlag(e)===d // PostHog flagsФичефлаги — PostHog remote.
Аналитика и observability
4 системы + consent. high
- Sentry (SvelteKit SDK): errors + tracing (
tracesSampleRate:1) + Session Replay (10% сессий / 100% при ошибке), releasemaster-dae5e30a, события воркеров туннелируются через/api/events(обход adblock),sendDefaultPii:true. - PostHog 1.376.0: self-proxy
a.takeprofit.com, autocapture, session recording, surveys, heatmaps, web-vitals, feature flags;person_profiles:"always"; сквознойtp_session_id(и в Sentry). - GA4
G-70RJGQTFX6(gtag.js), Reddit pixela2_dr4k0zki1xfa(только prod). - Termly cookie-consent/auto-blocker; пиксели гейтятся стором
$externalScriptsAdded.
AI-ассистент
Самописный клиент к бэкенду api/ai-chat/*; провайдер один — Anthropic (Claude). high
- Только Anthropic (
vg=["anthropic"]); OpenAI нет. Две группы моделей: серверные «Takeprofit Models» и пользовательские BYOK (provider:anthropic). - BYOK-ключ хранится на сервере (
api/ai-chat/api-keys/{{provider}}), не в браузере; для всехclaude-*моделей. - Streaming = SSE (ReadableStream + кастомный парсер): события started/text_delta/tool_call/tool_result/ui_tool/sub_*; отмена run.
- Контекст графика в каждом запросе: symbol/exchange/timeframe/timerange/drawings/indicators.
- 5 chart-actions, которые AI выполняет: change_timeframe, change_timerange, add/update/delete_drawing (+watchlist_add_symbol).
- Детектор языка вложений: Indie/Pine/MQL/Python. Скиллы (
api/ai-chat/skills) с requiresContext. AI inline-edit в IDE скриптов. - «MCP» в маркетинге ≠ Anthropic MCP — реального MCP-клиента в бандле нет (это серверный script-edit пайплайн).
const vg=["anthropic"];function pg(n){return vg.includes(n)}Единственный AI-провайдер — Anthropic.
switch(n.action){case"change_timeframe":...case"add_drawing":...case"delete_drawing":...}Действия AI над графиком.
Мобильная версия
Юзабельно, но это responsive web/PWA десктопного терминала — не отдельный мобильный продукт и не нативное приложение. high
Нативного приложения у takeprofit.com нет. Апы «Take Profit» на App Store / Google Play — это другие компании-однофамильцы (takeprofitapp.com; com.takeproft.trader от tprofit.io; «Take Profit – Smart AI Trading» от AlmazApp). Чарт-платформа = web/PWA, ссылок на сторы в бандлах нет.
- Грузит реальный терминал на телефоне — нет заглушки «use desktop», нет редиректа в стор.
- Viewport залочен от зума (
maximum-scale=1) +interactive-widget=resizes-content— жесты обрабатывает приложение. - Детект:
isMobile(85×),isTouch(25×),pointer:coarse,maxTouchPoints; Tailwind-брейкпоинты (sm:640 + 450/520/600/756). - Lumino → single-document mode: один виджет за раз с переключателем (вместо тесного тайлинга) — главная мобильная адаптация.
- Тач: touch-drag bridge (синтез DragEvent), пинч-зум, Touchpad-Overlay precision-рисования (long-tap edit/tap finish), kinetic-инерция только тач.
- Service worker зарегистрирован (PWA: обновления/кэш). Мобильные тулбары (toolbarMobile), нижний drawing-тулбар на графике.
Вердикт: на телефоне работает полноценный терминал с тач-рисованием и single-widget режимом — лучше «сжатого десктопа», но это pro-инструмент на малом экране; мульти-чарт неудобен, нативного приложения/оффлайна сверх SW нет.
Дизайн-система и темы
Собственная токен-система поверх Tailwind (префикс tw-). Цвета — wide-gamut display-p3 (5241 значение в CSS). high
- Два канала на токен:
--colors-X(полный цвет) и--colors-var-X(голый p3-триплет для alpha:color(display-p3 var(--colors-var-X) / 16%)). - 7 «семян» (background/text/rise/fall/accent/buy/sell) → 8 генераторов → десятки токенов (hover/active/translucent/invert).
- 15 тем: 11 dark / 5 light. Применение —
data-theme=<slug>на <html> + статический CSS; user-темы инжектят переменные инлайн. - Чарт-палитра — 22 токена (rise/fall + 20 именованных цветов для индикаторов). action-brand фиолетовый
(.466 0 1)— единый во всех темах. - System-тема через
matchMedia(prefers-color-scheme). Ключtakeprofit.theme.css-variables, экспортwindow.exportTheme.
Свотчи — приблизительная sRGB-проекция из display-p3 (bg / rise / fall / accent). Gold Rush — монохромное золото; Wen Moon — светлая сине-голубая; Red Dragon — near-black/красный.
documentElement.setAttribute("data-theme",slug); setProperty(`--colors-${s}`,...)Смена темы: data-theme + переменные.
color(display-p3 var(--colors-var-action-buy) / 16%)Alpha из общего p3-триплета.
Рыночное покрытие
TakeProfit агрегирует данные внешних провайдеров (сам не брокер/не источник). high (docs)
| Класс | Покрытие / провайдер |
|---|---|
| Equities & Funds | только США: NYSE, Nasdaq, CBOE (sub-penny акции исключены) |
| CFD (forex/indices/commodities/bonds/equities) | Pepperstone + Exness (EUR/USD, S&P500, Gold/WTI, US/EU Treasuries, AAPL/TSLA-CFD…) |
| Crypto | 70+ бирж (CEX+DEX): spot, derivatives, perpetual |
| DEX | Hyperliquid (~500 perp, on-chain ордербук) + Aster (~500 perp) |
- Топ крипто-CEX по числу пар: Yobit ~5350, MEXC ~3575, Binance ~1500–1700, KuCoin ~1300–1500, CoinEx ~1391, OKX ~700–900, Bybit ~600–700, Coinbase ~500+, Kraken ~250–300…
- Live order book (стакан) — через Bybit & Binance; тиковые данные 50–1000 — только Binance/Bybit/Pepperstone/Exness.
- Не покрыто: sub-penny акции (<$0.01), неамериканские акции как биржевые (только CFD), опционы/прямое владение.
Тарифы и лимиты
Две ступени: Free (биллинг-имя «Freeroll») и All-In (он же Premium/Pro в доках). high (docs)
| Фича | Free | All-In |
|---|---|---|
| Workspaces | 2 | ∞ |
| Алерты | 1 (истечение до 3 мес) | до 400 «вечных» cloud-алертов |
| Бэктест lookback | 5 000 свечей | 20 000 свечей |
| Tick-чарты | 1–49 тиков (все стримы) | 50–1000 тиков (Binance/Bybit/Pepperstone/Exness) |
| Custom timeframes / Indie / backtest | — | ✓ |
| Триал | 30 дней All-In без карты (one-time) | — |
- Нотификации: real-time 10/сек; email 1/мин на адрес; on-platform без лимита; webhook rate-limited.
- Биллинг — Stripe (вкладка Billing: апгрейд Freeroll→All-In, отмена, способы оплаты).
Born to Earn (монетизация)
Единый Monetization Hub (/monetization), 5 потоков заработка; «TakeProfit не тратит на рекламу — инвестирует в креаторов». high (docs)
| Поток | Standard | Maxx Ambassador |
|---|---|---|
| Revenue share (рефералы платформы) | 25% | 50% |
| Indie Marketplace (автор получает) | 80% (платформа 20%) | 100% (0%) |
| WidgetHub commission | 30% | 0% |
| Premium-посты fee | 10% | 0% |
| Продажи своим рефералам | 100% всегда | 100% всегда |
- Продажа индикаторов: только созданные в IDE (Indie); цена слайдером Free–$100; описание ≥100 символов; модерация 1–2 раб. дня; маркетплейс
/indicators. - Платные посты: «Only for Subscribers» или линия «Paid Content Below»; цена $1–$100/мес; нельзя повышать цену при активных подписчиках; снятие пейволла → авто-рефанд.
- Реферальная программа: 25% пожизненный rev-share с покупок платформы; 100% со своих продуктов рефералам.
Сообщество и Feed
high (docs)- Глобальный feed
/feed; шаринг скринеров/screens; маркетплейс индикаторов/indicators. - Посты: Title ≤120 симв., Subtitle ≤240; блоки через
/(параграфы/заголовки/списки/цитаты/код/картинки/embed); картинки ≤2MB; теги — любое число. - Embed: интерактивные chart/financials-виджеты в постах (zoom/expand/copy в свой workspace).
- Share Chart: 6 тем оформления, toggle Allow-to-copy, уникальный URL, Save as image (1920×1080, ≤1MB), партнёрская монетизация по ссылке.
Торговля (Beta) — по докам
Прямая торговля с графика. Статус Beta, только деривативы. high (docs)
- Биржи: нативно только Bybit (Binance «скоро»); Lime Trading (lime.co, NYC) — сторонний iframe-виджет (LimeOrder + Lime Portfolio). В коде есть ещё widget-интеграции J2T/Ilotcos (non-prod на finam.dev), но в доках их нет.
- Подключение Bybit: API key с правами Orders/Positions/Balance → Connect; авто-sync. Bybit EU (bybit.eu) не поддерживается.
- Типы: только Market/Limit (Stop Market/Limit — нет). TIF: только GTC. Trigger Price: Last/Mark/Index. TP/SL/RR, Reduce-Only.
- Chart-trading: drag уровней, визуальные TP/SL, RR на графике. Margin Cross/Isolated + Leverage.
- Account Widget: Equity/Available/Unrealized PnL; табы Assets/Positions/Open Orders/Order History/Trade History; двусторонний sync с биржей.
- Beta-лимиты: только One-Way (нет Hedge), нет редактирования ордеров (только отмена), настройки формы не сохраняются между сессиями, fees приблизительные.
Алерты и доставка — по докам
high (docs)- Триггеры (14): Moving Up/Down(+%), Crossing/Cross Up/Down, Greater/Lower Than, Entering/Exiting/Inside/Outside Channel; источник Price или Indicator; мульти-условные (AND, до 5 условий × 3 ряда). Хоткей Alt+A.
- Доставка: popup, email, Telegram (бот или свой webhook), Discord (webhook), generic webhook (POST JSON). IP-allowlist прокси:
32.196.192.252,52.70.159.39. - Переменные сообщения:
{{ticker}},{{exchange}},{{close}},{{time_frame}},{{condition_type}},{{condX.srcY}}(X∈0-4, Y∈0-2)… Режимы Plain Text / JSON. - Интеграции: Telegram/Discord/Slack/IFTTT/Zapier; WunderTrading (
wtalerts.com/bot/other). - Лимиты: Free 1 алерт (3 мес), Premium 400 вечных; статусы Active/Triggered/Expired/Stopped/Error; логи на весь lifetime.
Indie · AI · MCP — по докам
high (docs)
Indie (v5)
- Диалект Python для TA; декораторы
@indicator/@algorithm/@strategy; пакеты math/algorithms/drawings/plot/color/schedule/strategies + sortedcontainers/statistics/datetime; дженерикиSeries[T]. - Бэктест-механика: задержка исполнения (ордер применяется на следующем calc-тике),
intrabar_order_filter(NO_FILTER/ON_BAR_CLOSE/FIRST/LAST_IN_BAR), маржа initial/maintenance + margin call/stop-out. - 9 встроенных стратегий: ADX Breakout, Consecutive Up/Down, Inside/Outside Bar, MACD, Momentum, MA Cross, Price Channel, RSI. Метрики: Sharpe/Sortino/Calmar, VaR 95/99, Profit Factor, Expectancy…
AI-ассистент
- Лимит 5 запросов/мин; всегда отвечает по-английски; контекст из приложенных виджетов.
- 4 инструмента: Technical Analysis, Indie Scripts, Platform Guide, Risk & Position Sizing. Chart actions (accept/reject). IDE: Quick Edit (diff), Ask/Edit, Pine→Indie.
- Модели: системные + опц. свой Anthropic API-ключ для Claude.
MCP-сервер (публичный)
https://mcp.takeprofit.com/mcp(HTTP/remote) — внешние LLM пишут/конвертируют/валидируют/объясняют Indie-код + доступ к TOC доков.- Клиенты: Claude Desktop (custom connector), Claude Code CLI (
claude mcp add --transport http), Cursor, VSCode, mcp-remote для free-аккаунтов. Рекомендуют Claude Pro/Max, скрипты ≤200–300 строк. - Это отдельно от in-app AI-чата: MCP-сервер для ВНЕШНИХ клиентов (поэтому MCP-клиента в бандле фронта нет — и то, и другое верно).
Карта роутов
Публичные роуты SvelteKit (из node-манифеста). high
| Роут | Назначение |
|---|---|
| /platform | терминал (workspace) |
| /(media)/chart/[id] | шаринг графика |
| /(media)/feed · /feed/[tag] | лента сообщества |
| /(media)/indicators | маркетплейс индикаторов |
| /(media)/screens · /stock-screen/[slug] | шаринг скринеров |
| /(media)/financials/[id] | шаринг финансов |
| /(media)/u/[username] | профиль автора |
| /(media)/posts/[slug] | посты |
| /monetization/{build-indicators,craft-widgets,invite-friends,write-posts} | хабы заработка |
| /born-to-earn | Born to Earn |
| /mcp/authorize | OAuth для MCP |
| /(embed)/embed/docs/indie/[slug] · /(media)/docs/indie | доки Indie / embed |
| /settings/{account,billing,notification,profile} | настройки |
| /(landings)/features/charts · /(webflow)/beta | лендинги (Webflow) |
| /(legal)/{privacy,terms,cookie,oss-disclosure} | юридическое |
Диаграммы потоков
Поток данных
Поток авторизации
Рендер-пайплайн / архитектура UI
Пробелы и метод
Честные пробелы
- Клиентского WASM нет (0
.wasmво всём графе). «WASM C/C++» = серверный рантайм Indie (R_WASM). - Точные версии библиотек не извлекаются (version-строки вырезаны) — идентификация по сигнатурам.
- Точные hex именованных тем — в display-p3; свотчи здесь приблизительные (точные p3-триплеты есть в
dumps/). - Серверная сторона (Go/Bazel, /api/settings backend, обмен Stytch↔cookie) — вне клиентского бандла.
- Часть продуктовых событий аналитики шлётся через переменные-аргументы и не извлечена как статические строки.
Метод
Реверс публичных бандлов takeprofit.com/_app/immutable/: полное замыкание импортов — 352 JS-чанка / 12 МБ + 6 стрим-воркеров (2.8 МБ) + 46 CSS (1.1 МБ). Живой захват в демо-терминале (Playwright: клики/drag/инструментирование WebGL+rAF/перехват Connect-вызовов/мобильный вьюпорт). Параллельный разбор 30 подсистем агентами в 3 волны. Идентификация библиотек — по сигнатурам API/CSS/конфигов. Артефакты: ~/research/takeprofit-charts/ (bundles2/, workers/, css/, shots/, dumps/, extract/).