@orderly.network/ui-tradingview 3.1.2-alpha.1 → 3.1.3-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1171,11 +1171,13 @@ function getErrorMessage(error) {
1171
1171
  var HISTORY_PATH = "tv/history";
1172
1172
  var KLINE_HISTORY_PATH = "v1/tv/kline_history";
1173
1173
  var _HistoryProvider = class _HistoryProvider {
1174
- constructor(datafeedUrl, requester, limitedServerResponse) {
1174
+ constructor(datafeedUrl, requester, limitedServerResponse, getSymbolCreatedTime) {
1175
1175
  this._klinePreference = /* @__PURE__ */ new Map();
1176
+ this._createTimeBoundaryCutoff = /* @__PURE__ */ new Map();
1176
1177
  this._datafeedUrl = datafeedUrl;
1177
1178
  this._requester = requester;
1178
1179
  this._limitedServerResponse = limitedServerResponse;
1180
+ this._getSymbolCreatedTime = getSymbolCreatedTime;
1179
1181
  }
1180
1182
  /**
1181
1183
  * Build request parameters for history API calls
@@ -1217,18 +1219,32 @@ var _HistoryProvider = class _HistoryProvider {
1217
1219
  try {
1218
1220
  let result;
1219
1221
  let usedHistoryResult = false;
1222
+ if (this._shouldSkipRequestAtCreateTimeBoundary(
1223
+ symbolInfo,
1224
+ resolution,
1225
+ requestParams
1226
+ )) {
1227
+ resolve(this._createNoDataResult());
1228
+ return;
1229
+ }
1220
1230
  if (prefersKline) {
1221
- result = await this._requestKlineHistory(
1222
- this._buildKlineParams(requestParams, countBack)
1231
+ const klineParams = this._buildBoundedKlineParams(
1232
+ symbolInfo,
1233
+ resolution,
1234
+ requestParams,
1235
+ countBack
1223
1236
  );
1237
+ result = klineParams === null ? this._createNoDataResult() : await this._requestKlineHistory(klineParams.params);
1224
1238
  } else {
1225
1239
  const initialResponse = await this._requestHistory(requestParams);
1226
1240
  result = this._processHistoryResponse(initialResponse);
1227
1241
  usedHistoryResult = true;
1228
- const needsFallback = this._shouldFallbackToKline(
1229
- initialResponse,
1230
- countBack
1242
+ const reachedCreateTimeBoundary = this._markCreateTimeBoundaryIfReached(
1243
+ symbolInfo,
1244
+ resolution,
1245
+ result.bars
1231
1246
  );
1247
+ const needsFallback = !reachedCreateTimeBoundary && this._shouldFallbackToKline(initialResponse, countBack);
1232
1248
  if (needsFallback) {
1233
1249
  const earliestTime = this._getEarliestTime(result.bars);
1234
1250
  if (earliestTime !== null) {
@@ -1236,29 +1252,33 @@ var _HistoryProvider = class _HistoryProvider {
1236
1252
  0,
1237
1253
  countBack - result.bars.length
1238
1254
  );
1239
- const mergedResult = await this._tryKlineFallbackWithMerge(
1255
+ const fallbackOutcome = await this._tryKlineFallbackWithMerge(
1256
+ symbolInfo,
1257
+ resolution,
1240
1258
  requestParams,
1241
1259
  remainingCountBack,
1242
1260
  earliestTime,
1243
1261
  result
1244
1262
  );
1245
- if (mergedResult !== null) {
1246
- result = mergedResult;
1263
+ if (fallbackOutcome.status === "success") {
1264
+ result = fallbackOutcome.result;
1247
1265
  usedHistoryResult = false;
1248
1266
  this._klinePreference.set(preferenceKey, true);
1249
- } else {
1267
+ } else if (fallbackOutcome.status === "failed") {
1250
1268
  this._klinePreference.set(preferenceKey, false);
1251
1269
  }
1252
1270
  } else {
1253
- const klineResult = await this._tryKlineFallback(
1271
+ const fallbackOutcome = await this._tryKlineFallback(
1272
+ symbolInfo,
1273
+ resolution,
1254
1274
  requestParams,
1255
1275
  countBack
1256
1276
  );
1257
- if (klineResult !== null) {
1258
- result = klineResult;
1277
+ if (fallbackOutcome.status === "success") {
1278
+ result = fallbackOutcome.result;
1259
1279
  usedHistoryResult = false;
1260
1280
  this._klinePreference.set(preferenceKey, true);
1261
- } else {
1281
+ } else if (fallbackOutcome.status === "failed") {
1262
1282
  this._klinePreference.set(preferenceKey, false);
1263
1283
  }
1264
1284
  }
@@ -1266,6 +1286,11 @@ var _HistoryProvider = class _HistoryProvider {
1266
1286
  this._klinePreference.set(preferenceKey, false);
1267
1287
  }
1268
1288
  }
1289
+ this._markCreateTimeBoundaryIfReached(
1290
+ symbolInfo,
1291
+ resolution,
1292
+ result.bars
1293
+ );
1269
1294
  if (usedHistoryResult && this._limitedServerResponse) {
1270
1295
  await this._processTruncatedResponse(result, { ...requestParams });
1271
1296
  }
@@ -1475,6 +1500,13 @@ var _HistoryProvider = class _HistoryProvider {
1475
1500
  }
1476
1501
  return params;
1477
1502
  }
1503
+ _buildBoundedKlineParams(symbolInfo, resolution, requestParams, countBack) {
1504
+ return this._applyCreateTimeBoundaryToKlineParams(
1505
+ symbolInfo,
1506
+ resolution,
1507
+ this._buildKlineParams(requestParams, countBack)
1508
+ );
1509
+ }
1478
1510
  /**
1479
1511
  * Get the earliest time from bars array
1480
1512
  * @param bars - Array of bars
@@ -1496,22 +1528,38 @@ var _HistoryProvider = class _HistoryProvider {
1496
1528
  * @param historyResult - History result to merge with
1497
1529
  * @returns Merged result or null if kline request fails
1498
1530
  */
1499
- async _tryKlineFallbackWithMerge(requestParams, countBack, earliestTime, historyResult) {
1531
+ async _tryKlineFallbackWithMerge(symbolInfo, resolution, requestParams, countBack, earliestTime, historyResult) {
1500
1532
  try {
1533
+ if (this._hasReachedCreateTimeBoundary(symbolInfo, resolution, earliestTime)) {
1534
+ this._markCreateTimeBoundary(symbolInfo, resolution, earliestTime);
1535
+ return { status: "boundary" };
1536
+ }
1501
1537
  const klineParams = {
1502
1538
  ...requestParams,
1503
1539
  from: requestParams.from,
1504
1540
  to: earliestTime
1505
1541
  };
1542
+ const boundedKlineParams = this._buildBoundedKlineParams(
1543
+ symbolInfo,
1544
+ resolution,
1545
+ klineParams,
1546
+ countBack
1547
+ );
1548
+ if (boundedKlineParams === null) {
1549
+ return { status: "boundary" };
1550
+ }
1506
1551
  const klineResult = await this._requestKlineHistory(
1507
- this._buildKlineParams(klineParams, countBack)
1552
+ boundedKlineParams.params
1508
1553
  );
1509
1554
  if (klineResult.bars.length === 0) {
1510
- return null;
1555
+ return { status: "failed" };
1511
1556
  }
1512
- return this._mergeBars(historyResult, klineResult);
1557
+ return {
1558
+ status: "success",
1559
+ result: this._mergeBars(historyResult, klineResult)
1560
+ };
1513
1561
  } catch {
1514
- return null;
1562
+ return { status: "failed" };
1515
1563
  }
1516
1564
  }
1517
1565
  /**
@@ -1575,14 +1623,27 @@ var _HistoryProvider = class _HistoryProvider {
1575
1623
  meta
1576
1624
  };
1577
1625
  }
1578
- async _tryKlineFallback(requestParams, countBack) {
1626
+ async _tryKlineFallback(symbolInfo, resolution, requestParams, countBack) {
1579
1627
  try {
1580
- const result = await this._requestKlineHistory(
1581
- this._buildKlineParams(requestParams, countBack)
1628
+ const klineParams = this._buildBoundedKlineParams(
1629
+ symbolInfo,
1630
+ resolution,
1631
+ requestParams,
1632
+ countBack
1582
1633
  );
1583
- return result.bars.length > 0 ? result : null;
1634
+ if (klineParams === null) {
1635
+ return { status: "boundary" };
1636
+ }
1637
+ const result = await this._requestKlineHistory(klineParams.params);
1638
+ if (result.bars.length === 0) {
1639
+ return { status: "failed" };
1640
+ }
1641
+ return {
1642
+ status: "success",
1643
+ result
1644
+ };
1584
1645
  } catch {
1585
- return null;
1646
+ return { status: "failed" };
1586
1647
  }
1587
1648
  }
1588
1649
  _shouldFallbackToKline(response, expectedCount) {
@@ -1598,6 +1659,119 @@ var _HistoryProvider = class _HistoryProvider {
1598
1659
  }
1599
1660
  return false;
1600
1661
  }
1662
+ _applyCreateTimeBoundaryToKlineParams(symbolInfo, resolution, params) {
1663
+ const createdTimeSeconds = this._getSymbolCreatedTimeSeconds(symbolInfo);
1664
+ if (createdTimeSeconds === null) {
1665
+ return {
1666
+ params,
1667
+ clampedToCreateTime: false
1668
+ };
1669
+ }
1670
+ const to = this._getNumericParam(params, "to");
1671
+ if (to !== null && to <= createdTimeSeconds) {
1672
+ this._markCreateTimeBoundary(symbolInfo, resolution, createdTimeSeconds);
1673
+ return null;
1674
+ }
1675
+ const from = this._getNumericParam(params, "from");
1676
+ if (from !== null && from < createdTimeSeconds) {
1677
+ return {
1678
+ params: {
1679
+ ...params,
1680
+ from: createdTimeSeconds
1681
+ },
1682
+ clampedToCreateTime: true
1683
+ };
1684
+ }
1685
+ return {
1686
+ params,
1687
+ clampedToCreateTime: false
1688
+ };
1689
+ }
1690
+ _shouldSkipRequestAtCreateTimeBoundary(symbolInfo, resolution, params) {
1691
+ const createdTimeSeconds = this._getSymbolCreatedTimeSeconds(symbolInfo);
1692
+ if (createdTimeSeconds === null) {
1693
+ return false;
1694
+ }
1695
+ const to = this._getNumericParam(params, "to");
1696
+ if (to === null) {
1697
+ return false;
1698
+ }
1699
+ if (to <= createdTimeSeconds) {
1700
+ return true;
1701
+ }
1702
+ const cutoff = this._createTimeBoundaryCutoff.get(
1703
+ this._getPreferenceKey(symbolInfo, resolution)
1704
+ );
1705
+ return cutoff !== void 0 && to <= cutoff;
1706
+ }
1707
+ _markCreateTimeBoundaryIfReached(symbolInfo, resolution, bars) {
1708
+ const earliestTime = this._getEarliestTime(bars);
1709
+ if (earliestTime !== null && this._hasReachedCreateTimeBoundary(symbolInfo, resolution, earliestTime)) {
1710
+ this._markCreateTimeBoundary(symbolInfo, resolution, earliestTime);
1711
+ return true;
1712
+ }
1713
+ return false;
1714
+ }
1715
+ _markCreateTimeBoundary(symbolInfo, resolution, cutoffSeconds) {
1716
+ const key = this._getPreferenceKey(symbolInfo, resolution);
1717
+ const currentCutoff = this._createTimeBoundaryCutoff.get(key);
1718
+ if (currentCutoff === void 0 || cutoffSeconds > currentCutoff) {
1719
+ this._createTimeBoundaryCutoff.set(key, cutoffSeconds);
1720
+ }
1721
+ }
1722
+ _hasReachedCreateTimeBoundary(symbolInfo, resolution, earliestTimeSeconds) {
1723
+ const createdTimeSeconds = this._getSymbolCreatedTimeSeconds(symbolInfo);
1724
+ if (createdTimeSeconds === null) {
1725
+ return false;
1726
+ }
1727
+ return earliestTimeSeconds <= createdTimeSeconds + this._resolutionToSeconds(resolution);
1728
+ }
1729
+ _getSymbolCreatedTimeSeconds(symbolInfo) {
1730
+ const symbolInfoWithCreateTime = symbolInfo;
1731
+ const createdTime = symbolInfoWithCreateTime.created_time ?? this._getSymbolCreatedTime?.(symbolInfo);
1732
+ if (typeof createdTime !== "number" || !Number.isFinite(createdTime)) {
1733
+ return null;
1734
+ }
1735
+ return Math.floor(createdTime / 1e3);
1736
+ }
1737
+ _getNumericParam(params, key) {
1738
+ const value = params[key];
1739
+ if (Array.isArray(value)) {
1740
+ return null;
1741
+ }
1742
+ const numberValue = Number(value);
1743
+ return Number.isFinite(numberValue) ? numberValue : null;
1744
+ }
1745
+ _resolutionToSeconds(resolution) {
1746
+ const match = resolution.match(/^(\d*)([DWMY])?$/);
1747
+ if (!match) {
1748
+ return 60;
1749
+ }
1750
+ const amount = match[1] ? parseInt(match[1], 10) : 1;
1751
+ if (!Number.isFinite(amount) || amount <= 0) {
1752
+ return 60;
1753
+ }
1754
+ switch (match[2]) {
1755
+ case "D":
1756
+ return amount * 86400;
1757
+ case "W":
1758
+ return amount * 7 * 86400;
1759
+ case "M":
1760
+ return amount * 30 * 86400;
1761
+ case "Y":
1762
+ return amount * 365 * 86400;
1763
+ default:
1764
+ return amount * 60;
1765
+ }
1766
+ }
1767
+ _createNoDataResult() {
1768
+ return {
1769
+ bars: [],
1770
+ meta: {
1771
+ noData: true
1772
+ }
1773
+ };
1774
+ }
1601
1775
  };
1602
1776
  /**
1603
1777
  * Static mapping table for resolution conversion
@@ -1896,13 +2070,18 @@ function definedValueOrDefault(value, defaultValue) {
1896
2070
 
1897
2071
  // src/tradingviewAdapter/datafeed/abstract-datafeed.ts
1898
2072
  var AbstractDatafeed = class {
1899
- constructor(datafeedURL) {
2073
+ constructor(datafeedURL, options) {
1900
2074
  this._configuration = defaultConfiguration();
1901
2075
  this._symbolsStorage = null;
1902
2076
  this._historyCursor = null;
1903
2077
  this._datafeedURL = datafeedURL;
1904
2078
  this._requester = new Requester();
1905
- this._historyProvider = new HistoryProvider(datafeedURL, this._requester);
2079
+ this._historyProvider = new HistoryProvider(
2080
+ datafeedURL,
2081
+ this._requester,
2082
+ void 0,
2083
+ options?.getSymbolCreatedTime
2084
+ );
1906
2085
  this._configurationReadyPromise = this._requestConfiguration().then(
1907
2086
  (configuration) => {
1908
2087
  if (configuration === null) {
@@ -2276,9 +2455,9 @@ var getAutoIncrementId = /* @__PURE__ */ (() => {
2276
2455
  return () => id++;
2277
2456
  })();
2278
2457
  var Datafeed = class extends AbstractDatafeed {
2279
- constructor(apiUrl, ws) {
2458
+ constructor(apiUrl, ws, options) {
2280
2459
  const datafeedURL = `${apiUrl}`;
2281
- super(datafeedURL);
2460
+ super(datafeedURL, options);
2282
2461
  this.bbosMap = /* @__PURE__ */ new Map();
2283
2462
  this.tickersMap = /* @__PURE__ */ new Map();
2284
2463
  this.eventBus = new MultiBroadcastEventBus();
@@ -4448,14 +4627,40 @@ function useTradingviewScript(props) {
4448
4627
  const theme = props.theme ?? currentTheme?.mode ?? "dark";
4449
4628
  const cssVariables = useCssVariables(theme);
4450
4629
  const chart = React3.useRef(null);
4630
+ const [readyWidget, setReadyWidget] = React3.useState(
4631
+ null
4632
+ );
4451
4633
  const apiBaseUrl = hooks.useConfig("apiBaseUrl");
4452
4634
  const { state: accountState } = hooks.useAccount();
4453
4635
  const [side, setSide] = React3.useState(types.OrderSide.SELL);
4454
4636
  const symbolsInfo = hooks.useSymbolsInfo();
4637
+ const symbolsInfoRef = React3.useRef(symbolsInfo);
4455
4638
  const [fullscreen, setFullscreen] = hooks.useLocalStorage(
4456
4639
  types.TradingviewFullscreenKey,
4457
4640
  false
4458
4641
  );
4642
+ React3.useEffect(() => {
4643
+ symbolsInfoRef.current = symbolsInfo;
4644
+ }, [symbolsInfo]);
4645
+ const getSymbolCreatedTime = React3.useCallback(
4646
+ (symbolInfo) => {
4647
+ const candidates = [
4648
+ symbolInfo.ticker,
4649
+ symbolInfo.name,
4650
+ ...symbolInfo.base_name ?? []
4651
+ ].filter(
4652
+ (symbolName) => typeof symbolName === "string" && symbolName.length > 0
4653
+ ).map((symbolName) => withoutExchangePrefix(symbolName));
4654
+ for (const candidate of candidates) {
4655
+ const createdTime = symbolsInfoRef.current[candidate]?.("created_time");
4656
+ if (typeof createdTime === "number") {
4657
+ return createdTime;
4658
+ }
4659
+ }
4660
+ return void 0;
4661
+ },
4662
+ []
4663
+ );
4459
4664
  const { onSubmit, submitting } = hooks.useOrderEntry_deprecated(
4460
4665
  {
4461
4666
  symbol: symbol ?? "",
@@ -4524,7 +4729,8 @@ function useTradingviewScript(props) {
4524
4729
  symbol,
4525
4730
  order_type: types.OrderType.MARKET,
4526
4731
  side: side2,
4527
- reduce_only: true
4732
+ reduce_only: true,
4733
+ margin_mode: data.marginMode ?? data.margin_mode ?? marginMode ?? types.MarginMode.CROSS
4528
4734
  };
4529
4735
  setSide(side2);
4530
4736
  ui.modal.show("MarketCloseConfirmID", {
@@ -4686,7 +4892,7 @@ function useTradingviewScript(props) {
4686
4892
  toolbarBg,
4687
4893
  overrides,
4688
4894
  studiesOverrides,
4689
- datafeed: new Datafeed(apiBaseUrl, ws),
4895
+ datafeed: new Datafeed(apiBaseUrl, ws, { getSymbolCreatedTime }),
4690
4896
  contextMenu: {
4691
4897
  items_processor: async (defaultItems) => {
4692
4898
  return defaultItems;
@@ -4712,6 +4918,7 @@ function useTradingviewScript(props) {
4712
4918
  }
4713
4919
  return () => {
4714
4920
  chart.current?.remove();
4921
+ setReadyWidget(null);
4715
4922
  };
4716
4923
  }, [
4717
4924
  isMobile,
@@ -4729,7 +4936,8 @@ function useTradingviewScript(props) {
4729
4936
  loadingScreen,
4730
4937
  toolbarBg,
4731
4938
  customIndicatorsGetter,
4732
- direction
4939
+ direction,
4940
+ getSymbolCreatedTime
4733
4941
  ]);
4734
4942
  React3.useEffect(() => {
4735
4943
  ws.on(
@@ -4750,6 +4958,7 @@ function useTradingviewScript(props) {
4750
4958
  React3.useEffect(() => {
4751
4959
  if (chart.current && chart.current?.instance) {
4752
4960
  chart.current?.instance?.onChartReady(() => {
4961
+ setReadyWidget(chart.current?.instance ?? null);
4753
4962
  if (isLoggedIn && chart.current?.instance) {
4754
4963
  createRenderer(
4755
4964
  chart.current.instance,
@@ -4790,7 +4999,8 @@ function useTradingviewScript(props) {
4790
4999
  onFullScreenChange,
4791
5000
  classNames,
4792
5001
  direction,
4793
- fullscreen
5002
+ fullscreen,
5003
+ readyWidget
4794
5004
  };
4795
5005
  }
4796
5006
 
@@ -4864,6 +5074,10 @@ var InjectableTradingviewDesktop = ui.injectable(
4864
5074
  TradingviewChart,
4865
5075
  "TradingView.Desktop"
4866
5076
  );
5077
+ var InjectableChartOverlay = ui.injectable(
5078
+ () => null,
5079
+ "Trading.Chart.Overlay"
5080
+ );
4867
5081
  var LazyLineType = React3__default.default.lazy(() => Promise.resolve().then(() => (init_lineType(), lineType_exports)));
4868
5082
  var LazyTimeInterval = React3__default.default.lazy(
4869
5083
  () => Promise.resolve().then(() => (init_timeInterval(), timeInterval_exports)).then((mod) => ({ default: mod.TimeInterval }))
@@ -5066,7 +5280,16 @@ var TradingviewUI = React3.forwardRef((props, ref) => {
5066
5280
  onFullScreenChange
5067
5281
  }
5068
5282
  ) }),
5069
- /* @__PURE__ */ jsxRuntime.jsx(InjectableTradingviewDesktop, { ...props })
5283
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-relative oui-min-h-0 oui-flex-1", children: [
5284
+ /* @__PURE__ */ jsxRuntime.jsx(InjectableTradingviewDesktop, { ...props }),
5285
+ props.readyWidget && props.symbol && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-pointer-events-none oui-absolute oui-inset-0 oui-z-[2]", children: /* @__PURE__ */ jsxRuntime.jsx(
5286
+ InjectableChartOverlay,
5287
+ {
5288
+ widget: props.readyWidget,
5289
+ symbol: props.symbol
5290
+ }
5291
+ ) })
5292
+ ] })
5070
5293
  ]
5071
5294
  }
5072
5295
  )
@@ -5081,6 +5304,7 @@ var TradingviewWidget = React3.forwardRef((props, ref) => {
5081
5304
  // src/index.ts
5082
5305
  init_displayControl();
5083
5306
 
5307
+ exports.InjectableChartOverlay = InjectableChartOverlay;
5084
5308
  exports.InjectableTradingviewDesktop = InjectableTradingviewDesktop;
5085
5309
  exports.TradingviewUI = TradingviewUI;
5086
5310
  exports.TradingviewWidget = TradingviewWidget;