From d6090d28ec547689ed3d3024daa8f9fa158d6b53 Mon Sep 17 00:00:00 2001 From: tlauria Date: Tue, 19 Dec 2023 18:24:04 +0100 Subject: [PATCH 1/2] feat: youngplatform --- ts/src/abstract/youngplatform.ts | 678 +++ ts/src/youngplatform.ts | 9527 ++++++++++++++++++++++++++++++ 2 files changed, 10205 insertions(+) create mode 100644 ts/src/abstract/youngplatform.ts create mode 100644 ts/src/youngplatform.ts diff --git a/ts/src/abstract/youngplatform.ts b/ts/src/abstract/youngplatform.ts new file mode 100644 index 0000000000000..22c71a9adef49 --- /dev/null +++ b/ts/src/abstract/youngplatform.ts @@ -0,0 +1,678 @@ +// ------------------------------------------------------------------------------- + +// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: +// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code + +// ------------------------------------------------------------------------------- + +import { implicitReturnType } from '../base/types.js'; +import { Exchange as _Exchange } from '../base/Exchange.js'; + +interface Exchange { + sapiGetSystemStatus (params?: {}): Promise; + sapiGetAccountSnapshot (params?: {}): Promise; + sapiGetMarginAsset (params?: {}): Promise; + sapiGetMarginPair (params?: {}): Promise; + sapiGetMarginAllAssets (params?: {}): Promise; + sapiGetMarginAllPairs (params?: {}): Promise; + sapiGetMarginPriceIndex (params?: {}): Promise; + sapiGetAssetAssetDividend (params?: {}): Promise; + sapiGetAssetDribblet (params?: {}): Promise; + sapiGetAssetTransfer (params?: {}): Promise; + sapiGetAssetAssetDetail (params?: {}): Promise; + sapiGetAssetTradeFee (params?: {}): Promise; + sapiGetAssetLedgerTransferCloudMiningQueryByPage (params?: {}): Promise; + sapiGetAssetConvertTransferQueryByPage (params?: {}): Promise; + sapiGetAssetWalletBalance (params?: {}): Promise; + sapiGetAssetCustodyTransferHistory (params?: {}): Promise; + sapiGetMarginLoan (params?: {}): Promise; + sapiGetMarginRepay (params?: {}): Promise; + sapiGetMarginAccount (params?: {}): Promise; + sapiGetMarginTransfer (params?: {}): Promise; + sapiGetMarginInterestHistory (params?: {}): Promise; + sapiGetMarginForceLiquidationRec (params?: {}): Promise; + sapiGetMarginOrder (params?: {}): Promise; + sapiGetMarginOpenOrders (params?: {}): Promise; + sapiGetMarginAllOrders (params?: {}): Promise; + sapiGetMarginMyTrades (params?: {}): Promise; + sapiGetMarginMaxBorrowable (params?: {}): Promise; + sapiGetMarginMaxTransferable (params?: {}): Promise; + sapiGetMarginTradeCoeff (params?: {}): Promise; + sapiGetMarginIsolatedTransfer (params?: {}): Promise; + sapiGetMarginIsolatedAccount (params?: {}): Promise; + sapiGetMarginIsolatedPair (params?: {}): Promise; + sapiGetMarginIsolatedAllPairs (params?: {}): Promise; + sapiGetMarginIsolatedAccountLimit (params?: {}): Promise; + sapiGetMarginInterestRateHistory (params?: {}): Promise; + sapiGetMarginOrderList (params?: {}): Promise; + sapiGetMarginAllOrderList (params?: {}): Promise; + sapiGetMarginOpenOrderList (params?: {}): Promise; + sapiGetMarginCrossMarginData (params?: {}): Promise; + sapiGetMarginIsolatedMarginData (params?: {}): Promise; + sapiGetMarginIsolatedMarginTier (params?: {}): Promise; + sapiGetMarginRateLimitOrder (params?: {}): Promise; + sapiGetMarginDribblet (params?: {}): Promise; + sapiGetMarginDust (params?: {}): Promise; + sapiGetMarginCrossMarginCollateralRatio (params?: {}): Promise; + sapiGetMarginExchangeSmallLiability (params?: {}): Promise; + sapiGetMarginExchangeSmallLiabilityHistory (params?: {}): Promise; + sapiGetMarginNextHourlyInterestRate (params?: {}): Promise; + sapiGetMarginCapitalFlow (params?: {}): Promise; + sapiGetMarginDelistSchedule (params?: {}): Promise; + sapiGetMarginAvailableInventory (params?: {}): Promise; + sapiGetMarginLeverageBracket (params?: {}): Promise; + sapiGetLoanVipLoanableData (params?: {}): Promise; + sapiGetLoanVipCollateralData (params?: {}): Promise; + sapiGetLoanVipRequestData (params?: {}): Promise; + sapiGetLoanVipRequestInterestRate (params?: {}): Promise; + sapiGetLoanIncome (params?: {}): Promise; + sapiGetLoanOngoingOrders (params?: {}): Promise; + sapiGetLoanLtvAdjustmentHistory (params?: {}): Promise; + sapiGetLoanBorrowHistory (params?: {}): Promise; + sapiGetLoanRepayHistory (params?: {}): Promise; + sapiGetLoanLoanableData (params?: {}): Promise; + sapiGetLoanCollateralData (params?: {}): Promise; + sapiGetLoanRepayCollateralRate (params?: {}): Promise; + sapiGetLoanFlexibleOngoingOrders (params?: {}): Promise; + sapiGetLoanFlexibleBorrowHistory (params?: {}): Promise; + sapiGetLoanFlexibleRepayHistory (params?: {}): Promise; + sapiGetLoanFlexibleLtvAdjustmentHistory (params?: {}): Promise; + sapiGetLoanFlexibleLoanableData (params?: {}): Promise; + sapiGetLoanFlexibleCollateralData (params?: {}): Promise; + sapiGetLoanVipOngoingOrders (params?: {}): Promise; + sapiGetLoanVipRepayHistory (params?: {}): Promise; + sapiGetLoanVipCollateralAccount (params?: {}): Promise; + sapiGetFiatOrders (params?: {}): Promise; + sapiGetFiatPayments (params?: {}): Promise; + sapiGetFuturesTransfer (params?: {}): Promise; + sapiGetFuturesHistDataLink (params?: {}): Promise; + sapiGetRebateTaxQuery (params?: {}): Promise; + sapiGetCapitalConfigGetall (params?: {}): Promise; + sapiGetCapitalDepositAddress (params?: {}): Promise; + sapiGetCapitalDepositAddressList (params?: {}): Promise; + sapiGetCapitalDepositHisrec (params?: {}): Promise; + sapiGetCapitalDepositSubAddress (params?: {}): Promise; + sapiGetCapitalDepositSubHisrec (params?: {}): Promise; + sapiGetCapitalWithdrawHistory (params?: {}): Promise; + sapiGetCapitalContractConvertibleCoins (params?: {}): Promise; + sapiGetConvertTradeFlow (params?: {}): Promise; + sapiGetConvertExchangeInfo (params?: {}): Promise; + sapiGetConvertAssetInfo (params?: {}): Promise; + sapiGetConvertOrderStatus (params?: {}): Promise; + sapiGetAccountStatus (params?: {}): Promise; + sapiGetAccountApiTradingStatus (params?: {}): Promise; + sapiGetAccountApiRestrictionsIpRestriction (params?: {}): Promise; + sapiGetBnbBurn (params?: {}): Promise; + sapiGetSubAccountFuturesAccount (params?: {}): Promise; + sapiGetSubAccountFuturesAccountSummary (params?: {}): Promise; + sapiGetSubAccountFuturesPositionRisk (params?: {}): Promise; + sapiGetSubAccountFuturesInternalTransfer (params?: {}): Promise; + sapiGetSubAccountList (params?: {}): Promise; + sapiGetSubAccountMarginAccount (params?: {}): Promise; + sapiGetSubAccountMarginAccountSummary (params?: {}): Promise; + sapiGetSubAccountSpotSummary (params?: {}): Promise; + sapiGetSubAccountStatus (params?: {}): Promise; + sapiGetSubAccountSubTransferHistory (params?: {}): Promise; + sapiGetSubAccountTransferSubUserHistory (params?: {}): Promise; + sapiGetSubAccountUniversalTransfer (params?: {}): Promise; + sapiGetSubAccountApiRestrictionsIpRestrictionThirdPartyList (params?: {}): Promise; + sapiGetSubAccountTransactionStatistics (params?: {}): Promise; + sapiGetSubAccountSubAccountApiIpRestriction (params?: {}): Promise; + sapiGetManagedSubaccountAsset (params?: {}): Promise; + sapiGetManagedSubaccountAccountSnapshot (params?: {}): Promise; + sapiGetManagedSubaccountQueryTransLogForInvestor (params?: {}): Promise; + sapiGetManagedSubaccountQueryTransLogForTradeParent (params?: {}): Promise; + sapiGetManagedSubaccountFetchFutureAsset (params?: {}): Promise; + sapiGetManagedSubaccountMarginAsset (params?: {}): Promise; + sapiGetManagedSubaccountInfo (params?: {}): Promise; + sapiGetManagedSubaccountDepositAddress (params?: {}): Promise; + sapiGetManagedSubaccountQueryTransLog (params?: {}): Promise; + sapiGetLendingDailyProductList (params?: {}): Promise; + sapiGetLendingDailyUserLeftQuota (params?: {}): Promise; + sapiGetLendingDailyUserRedemptionQuota (params?: {}): Promise; + sapiGetLendingDailyTokenPosition (params?: {}): Promise; + sapiGetLendingUnionAccount (params?: {}): Promise; + sapiGetLendingUnionPurchaseRecord (params?: {}): Promise; + sapiGetLendingUnionRedemptionRecord (params?: {}): Promise; + sapiGetLendingUnionInterestHistory (params?: {}): Promise; + sapiGetLendingProjectList (params?: {}): Promise; + sapiGetLendingProjectPositionList (params?: {}): Promise; + sapiGetMiningPubAlgoList (params?: {}): Promise; + sapiGetMiningPubCoinList (params?: {}): Promise; + sapiGetMiningWorkerDetail (params?: {}): Promise; + sapiGetMiningWorkerList (params?: {}): Promise; + sapiGetMiningPaymentList (params?: {}): Promise; + sapiGetMiningStatisticsUserStatus (params?: {}): Promise; + sapiGetMiningStatisticsUserList (params?: {}): Promise; + sapiGetMiningPaymentUid (params?: {}): Promise; + sapiGetBswapPools (params?: {}): Promise; + sapiGetBswapLiquidity (params?: {}): Promise; + sapiGetBswapLiquidityOps (params?: {}): Promise; + sapiGetBswapQuote (params?: {}): Promise; + sapiGetBswapSwap (params?: {}): Promise; + sapiGetBswapPoolConfigure (params?: {}): Promise; + sapiGetBswapAddLiquidityPreview (params?: {}): Promise; + sapiGetBswapRemoveLiquidityPreview (params?: {}): Promise; + sapiGetBswapUnclaimedRewards (params?: {}): Promise; + sapiGetBswapClaimedHistory (params?: {}): Promise; + sapiGetBlvtTokenInfo (params?: {}): Promise; + sapiGetBlvtSubscribeRecord (params?: {}): Promise; + sapiGetBlvtRedeemRecord (params?: {}): Promise; + sapiGetBlvtUserLimit (params?: {}): Promise; + sapiGetApiReferralIfNewUser (params?: {}): Promise; + sapiGetApiReferralCustomization (params?: {}): Promise; + sapiGetApiReferralUserCustomization (params?: {}): Promise; + sapiGetApiReferralRebateRecentRecord (params?: {}): Promise; + sapiGetApiReferralRebateHistoricalRecord (params?: {}): Promise; + sapiGetApiReferralKickbackRecentRecord (params?: {}): Promise; + sapiGetApiReferralKickbackHistoricalRecord (params?: {}): Promise; + sapiGetBrokerSubAccountApi (params?: {}): Promise; + sapiGetBrokerSubAccount (params?: {}): Promise; + sapiGetBrokerSubAccountApiCommissionFutures (params?: {}): Promise; + sapiGetBrokerSubAccountApiCommissionCoinFutures (params?: {}): Promise; + sapiGetBrokerInfo (params?: {}): Promise; + sapiGetBrokerTransfer (params?: {}): Promise; + sapiGetBrokerTransferFutures (params?: {}): Promise; + sapiGetBrokerRebateRecentRecord (params?: {}): Promise; + sapiGetBrokerRebateHistoricalRecord (params?: {}): Promise; + sapiGetBrokerSubAccountBnbBurnStatus (params?: {}): Promise; + sapiGetBrokerSubAccountDepositHist (params?: {}): Promise; + sapiGetBrokerSubAccountSpotSummary (params?: {}): Promise; + sapiGetBrokerSubAccountMarginSummary (params?: {}): Promise; + sapiGetBrokerSubAccountFuturesSummary (params?: {}): Promise; + sapiGetBrokerRebateFuturesRecentRecord (params?: {}): Promise; + sapiGetBrokerSubAccountApiIpRestriction (params?: {}): Promise; + sapiGetBrokerUniversalTransfer (params?: {}): Promise; + sapiGetAccountApiRestrictions (params?: {}): Promise; + sapiGetC2cOrderMatchListUserOrderHistory (params?: {}): Promise; + sapiGetNftHistoryTransactions (params?: {}): Promise; + sapiGetNftHistoryDeposit (params?: {}): Promise; + sapiGetNftHistoryWithdraw (params?: {}): Promise; + sapiGetNftUserGetAsset (params?: {}): Promise; + sapiGetPayTransactions (params?: {}): Promise; + sapiGetGiftcardVerify (params?: {}): Promise; + sapiGetGiftcardCryptographyRsaPublicKey (params?: {}): Promise; + sapiGetGiftcardBuyCodeTokenLimit (params?: {}): Promise; + sapiGetAlgoSpotOpenOrders (params?: {}): Promise; + sapiGetAlgoSpotHistoricalOrders (params?: {}): Promise; + sapiGetAlgoSpotSubOrders (params?: {}): Promise; + sapiGetAlgoFuturesOpenOrders (params?: {}): Promise; + sapiGetAlgoFuturesHistoricalOrders (params?: {}): Promise; + sapiGetAlgoFuturesSubOrders (params?: {}): Promise; + sapiGetPortfolioAccount (params?: {}): Promise; + sapiGetPortfolioCollateralRate (params?: {}): Promise; + sapiGetPortfolioPmLoan (params?: {}): Promise; + sapiGetPortfolioInterestHistory (params?: {}): Promise; + sapiGetPortfolioAssetIndexPrice (params?: {}): Promise; + sapiGetPortfolioRepayFuturesSwitch (params?: {}): Promise; + sapiGetPortfolioMarginAssetLeverage (params?: {}): Promise; + sapiGetStakingProductList (params?: {}): Promise; + sapiGetStakingPosition (params?: {}): Promise; + sapiGetStakingStakingRecord (params?: {}): Promise; + sapiGetStakingPersonalLeftQuota (params?: {}): Promise; + sapiGetLendingAutoInvestTargetAssetList (params?: {}): Promise; + sapiGetLendingAutoInvestTargetAssetRoiList (params?: {}): Promise; + sapiGetLendingAutoInvestAllAsset (params?: {}): Promise; + sapiGetLendingAutoInvestSourceAssetList (params?: {}): Promise; + sapiGetLendingAutoInvestPlanList (params?: {}): Promise; + sapiGetLendingAutoInvestPlanId (params?: {}): Promise; + sapiGetLendingAutoInvestHistoryList (params?: {}): Promise; + sapiGetLendingAutoInvestIndexInfo (params?: {}): Promise; + sapiGetLendingAutoInvestIndexUserSummary (params?: {}): Promise; + sapiGetLendingAutoInvestOneOffStatus (params?: {}): Promise; + sapiGetLendingAutoInvestRedeemHistory (params?: {}): Promise; + sapiGetLendingAutoInvestRebalanceHistory (params?: {}): Promise; + sapiGetSimpleEarnFlexibleList (params?: {}): Promise; + sapiGetSimpleEarnLockedList (params?: {}): Promise; + sapiGetSimpleEarnFlexiblePersonalLeftQuota (params?: {}): Promise; + sapiGetSimpleEarnLockedPersonalLeftQuota (params?: {}): Promise; + sapiGetSimpleEarnFlexibleSubscriptionPreview (params?: {}): Promise; + sapiGetSimpleEarnLockedSubscriptionPreview (params?: {}): Promise; + sapiGetSimpleEarnFlexibleHistoryRateHistory (params?: {}): Promise; + sapiGetSimpleEarnFlexiblePosition (params?: {}): Promise; + sapiGetSimpleEarnLockedPosition (params?: {}): Promise; + sapiGetSimpleEarnAccount (params?: {}): Promise; + sapiGetSimpleEarnFlexibleHistorySubscriptionRecord (params?: {}): Promise; + sapiGetSimpleEarnLockedHistorySubscriptionRecord (params?: {}): Promise; + sapiGetSimpleEarnFlexibleHistoryRedemptionRecord (params?: {}): Promise; + sapiGetSimpleEarnLockedHistoryRedemptionRecord (params?: {}): Promise; + sapiGetSimpleEarnFlexibleHistoryRewardsRecord (params?: {}): Promise; + sapiGetSimpleEarnLockedHistoryRewardsRecord (params?: {}): Promise; + sapiGetSimpleEarnFlexibleHistoryCollateralRecord (params?: {}): Promise; + sapiPostAssetDust (params?: {}): Promise; + sapiPostAssetDustBtc (params?: {}): Promise; + sapiPostAssetTransfer (params?: {}): Promise; + sapiPostAssetGetFundingAsset (params?: {}): Promise; + sapiPostAssetConvertTransfer (params?: {}): Promise; + sapiPostAccountDisableFastWithdrawSwitch (params?: {}): Promise; + sapiPostAccountEnableFastWithdrawSwitch (params?: {}): Promise; + sapiPostCapitalWithdrawApply (params?: {}): Promise; + sapiPostCapitalContractConvertibleCoins (params?: {}): Promise; + sapiPostCapitalDepositCreditApply (params?: {}): Promise; + sapiPostMarginTransfer (params?: {}): Promise; + sapiPostMarginLoan (params?: {}): Promise; + sapiPostMarginRepay (params?: {}): Promise; + sapiPostMarginOrder (params?: {}): Promise; + sapiPostMarginOrderOco (params?: {}): Promise; + sapiPostMarginDust (params?: {}): Promise; + sapiPostMarginExchangeSmallLiability (params?: {}): Promise; + sapiPostMarginIsolatedTransfer (params?: {}): Promise; + sapiPostMarginIsolatedAccount (params?: {}): Promise; + sapiPostMarginMaxLeverage (params?: {}): Promise; + sapiPostBnbBurn (params?: {}): Promise; + sapiPostSubAccountVirtualSubAccount (params?: {}): Promise; + sapiPostSubAccountMarginTransfer (params?: {}): Promise; + sapiPostSubAccountMarginEnable (params?: {}): Promise; + sapiPostSubAccountFuturesEnable (params?: {}): Promise; + sapiPostSubAccountFuturesTransfer (params?: {}): Promise; + sapiPostSubAccountFuturesInternalTransfer (params?: {}): Promise; + sapiPostSubAccountTransferSubToSub (params?: {}): Promise; + sapiPostSubAccountTransferSubToMaster (params?: {}): Promise; + sapiPostSubAccountUniversalTransfer (params?: {}): Promise; + sapiPostSubAccountOptionsEnable (params?: {}): Promise; + sapiPostManagedSubaccountDeposit (params?: {}): Promise; + sapiPostManagedSubaccountWithdraw (params?: {}): Promise; + sapiPostUserDataStream (params?: {}): Promise; + sapiPostUserDataStreamIsolated (params?: {}): Promise; + sapiPostFuturesTransfer (params?: {}): Promise; + sapiPostLendingCustomizedFixedPurchase (params?: {}): Promise; + sapiPostLendingDailyPurchase (params?: {}): Promise; + sapiPostLendingDailyRedeem (params?: {}): Promise; + sapiPostBswapLiquidityAdd (params?: {}): Promise; + sapiPostBswapLiquidityRemove (params?: {}): Promise; + sapiPostBswapSwap (params?: {}): Promise; + sapiPostBswapClaimRewards (params?: {}): Promise; + sapiPostBlvtSubscribe (params?: {}): Promise; + sapiPostBlvtRedeem (params?: {}): Promise; + sapiPostApiReferralCustomization (params?: {}): Promise; + sapiPostApiReferralUserCustomization (params?: {}): Promise; + sapiPostApiReferralRebateHistoricalRecord (params?: {}): Promise; + sapiPostApiReferralKickbackHistoricalRecord (params?: {}): Promise; + sapiPostBrokerSubAccount (params?: {}): Promise; + sapiPostBrokerSubAccountMargin (params?: {}): Promise; + sapiPostBrokerSubAccountFutures (params?: {}): Promise; + sapiPostBrokerSubAccountApi (params?: {}): Promise; + sapiPostBrokerSubAccountApiPermission (params?: {}): Promise; + sapiPostBrokerSubAccountApiCommission (params?: {}): Promise; + sapiPostBrokerSubAccountApiCommissionFutures (params?: {}): Promise; + sapiPostBrokerSubAccountApiCommissionCoinFutures (params?: {}): Promise; + sapiPostBrokerTransfer (params?: {}): Promise; + sapiPostBrokerTransferFutures (params?: {}): Promise; + sapiPostBrokerRebateHistoricalRecord (params?: {}): Promise; + sapiPostBrokerSubAccountBnbBurnSpot (params?: {}): Promise; + sapiPostBrokerSubAccountBnbBurnMarginInterest (params?: {}): Promise; + sapiPostBrokerSubAccountBlvt (params?: {}): Promise; + sapiPostBrokerSubAccountApiIpRestriction (params?: {}): Promise; + sapiPostBrokerSubAccountApiIpRestrictionIpList (params?: {}): Promise; + sapiPostBrokerUniversalTransfer (params?: {}): Promise; + sapiPostBrokerSubAccountApiPermissionUniversalTransfer (params?: {}): Promise; + sapiPostBrokerSubAccountApiPermissionVanillaOptions (params?: {}): Promise; + sapiPostGiftcardCreateCode (params?: {}): Promise; + sapiPostGiftcardRedeemCode (params?: {}): Promise; + sapiPostGiftcardBuyCode (params?: {}): Promise; + sapiPostAlgoSpotNewOrderTwap (params?: {}): Promise; + sapiPostAlgoFuturesNewOrderVp (params?: {}): Promise; + sapiPostAlgoFuturesNewOrderTwap (params?: {}): Promise; + sapiPostStakingPurchase (params?: {}): Promise; + sapiPostStakingRedeem (params?: {}): Promise; + sapiPostStakingSetAutoStaking (params?: {}): Promise; + sapiPostPortfolioRepay (params?: {}): Promise; + sapiPostLoanVipRenew (params?: {}): Promise; + sapiPostLoanVipBorrow (params?: {}): Promise; + sapiPostLoanBorrow (params?: {}): Promise; + sapiPostLoanRepay (params?: {}): Promise; + sapiPostLoanAdjustLtv (params?: {}): Promise; + sapiPostLoanCustomizeMarginCall (params?: {}): Promise; + sapiPostLoanFlexibleBorrow (params?: {}): Promise; + sapiPostLoanFlexibleRepay (params?: {}): Promise; + sapiPostLoanFlexibleAdjustLtv (params?: {}): Promise; + sapiPostLoanVipRepay (params?: {}): Promise; + sapiPostConvertGetQuote (params?: {}): Promise; + sapiPostConvertAcceptQuote (params?: {}): Promise; + sapiPostPortfolioAutoCollection (params?: {}): Promise; + sapiPostPortfolioAssetCollection (params?: {}): Promise; + sapiPostPortfolioBnbTransfer (params?: {}): Promise; + sapiPostPortfolioRepayFuturesSwitch (params?: {}): Promise; + sapiPostPortfolioRepayFuturesNegativeBalance (params?: {}): Promise; + sapiPostLendingAutoInvestPlanAdd (params?: {}): Promise; + sapiPostLendingAutoInvestPlanEdit (params?: {}): Promise; + sapiPostLendingAutoInvestPlanEditStatus (params?: {}): Promise; + sapiPostLendingAutoInvestOneOff (params?: {}): Promise; + sapiPostLendingAutoInvestRedeem (params?: {}): Promise; + sapiPostSimpleEarnFlexibleSubscribe (params?: {}): Promise; + sapiPostSimpleEarnLockedSubscribe (params?: {}): Promise; + sapiPostSimpleEarnFlexibleRedeem (params?: {}): Promise; + sapiPostSimpleEarnLockedRedeem (params?: {}): Promise; + sapiPostSimpleEarnFlexibleSetAutoSubscribe (params?: {}): Promise; + sapiPostSimpleEarnLockedSetAutoSubscribe (params?: {}): Promise; + sapiPutUserDataStream (params?: {}): Promise; + sapiPutUserDataStreamIsolated (params?: {}): Promise; + sapiDeleteMarginOpenOrders (params?: {}): Promise; + sapiDeleteMarginOrder (params?: {}): Promise; + sapiDeleteMarginOrderList (params?: {}): Promise; + sapiDeleteMarginIsolatedAccount (params?: {}): Promise; + sapiDeleteUserDataStream (params?: {}): Promise; + sapiDeleteUserDataStreamIsolated (params?: {}): Promise; + sapiDeleteBrokerSubAccountApi (params?: {}): Promise; + sapiDeleteBrokerSubAccountApiIpRestrictionIpList (params?: {}): Promise; + sapiDeleteAlgoSpotOrder (params?: {}): Promise; + sapiDeleteAlgoFuturesOrder (params?: {}): Promise; + sapiDeleteSubAccountSubAccountApiIpRestrictionIpList (params?: {}): Promise; + sapiV2GetSubAccountFuturesAccount (params?: {}): Promise; + sapiV2GetSubAccountFuturesAccountSummary (params?: {}): Promise; + sapiV2GetSubAccountFuturesPositionRisk (params?: {}): Promise; + sapiV2PostSubAccountSubAccountApiIpRestriction (params?: {}): Promise; + sapiV3GetSubAccountAssets (params?: {}): Promise; + sapiV3PostAssetGetUserAsset (params?: {}): Promise; + sapiV4GetSubAccountAssets (params?: {}): Promise; + dapiPublicGetPing (params?: {}): Promise; + dapiPublicGetTime (params?: {}): Promise; + dapiPublicGetExchangeInfo (params?: {}): Promise; + dapiPublicGetDepth (params?: {}): Promise; + dapiPublicGetTrades (params?: {}): Promise; + dapiPublicGetHistoricalTrades (params?: {}): Promise; + dapiPublicGetAggTrades (params?: {}): Promise; + dapiPublicGetPremiumIndex (params?: {}): Promise; + dapiPublicGetFundingRate (params?: {}): Promise; + dapiPublicGetKlines (params?: {}): Promise; + dapiPublicGetContinuousKlines (params?: {}): Promise; + dapiPublicGetIndexPriceKlines (params?: {}): Promise; + dapiPublicGetMarkPriceKlines (params?: {}): Promise; + dapiPublicGetPremiumIndexKlines (params?: {}): Promise; + dapiPublicGetTicker24hr (params?: {}): Promise; + dapiPublicGetTickerPrice (params?: {}): Promise; + dapiPublicGetTickerBookTicker (params?: {}): Promise; + dapiPublicGetConstituents (params?: {}): Promise; + dapiPublicGetOpenInterest (params?: {}): Promise; + dapiDataGetDeliveryPrice (params?: {}): Promise; + dapiDataGetOpenInterestHist (params?: {}): Promise; + dapiDataGetTopLongShortAccountRatio (params?: {}): Promise; + dapiDataGetTopLongShortPositionRatio (params?: {}): Promise; + dapiDataGetGlobalLongShortAccountRatio (params?: {}): Promise; + dapiDataGetTakerBuySellVol (params?: {}): Promise; + dapiDataGetBasis (params?: {}): Promise; + dapiPrivateGetPositionSideDual (params?: {}): Promise; + dapiPrivateGetOrderAmendment (params?: {}): Promise; + dapiPrivateGetOrder (params?: {}): Promise; + dapiPrivateGetOpenOrder (params?: {}): Promise; + dapiPrivateGetOpenOrders (params?: {}): Promise; + dapiPrivateGetAllOrders (params?: {}): Promise; + dapiPrivateGetBalance (params?: {}): Promise; + dapiPrivateGetAccount (params?: {}): Promise; + dapiPrivateGetPositionMarginHistory (params?: {}): Promise; + dapiPrivateGetPositionRisk (params?: {}): Promise; + dapiPrivateGetUserTrades (params?: {}): Promise; + dapiPrivateGetIncome (params?: {}): Promise; + dapiPrivateGetLeverageBracket (params?: {}): Promise; + dapiPrivateGetForceOrders (params?: {}): Promise; + dapiPrivateGetAdlQuantile (params?: {}): Promise; + dapiPrivateGetCommissionRate (params?: {}): Promise; + dapiPrivateGetIncomeAsyn (params?: {}): Promise; + dapiPrivateGetIncomeAsynId (params?: {}): Promise; + dapiPrivateGetPmExchangeInfo (params?: {}): Promise; + dapiPrivateGetPmAccountInfo (params?: {}): Promise; + dapiPrivatePostPositionSideDual (params?: {}): Promise; + dapiPrivatePostOrder (params?: {}): Promise; + dapiPrivatePostBatchOrders (params?: {}): Promise; + dapiPrivatePostCountdownCancelAll (params?: {}): Promise; + dapiPrivatePostLeverage (params?: {}): Promise; + dapiPrivatePostMarginType (params?: {}): Promise; + dapiPrivatePostPositionMargin (params?: {}): Promise; + dapiPrivatePostListenKey (params?: {}): Promise; + dapiPrivatePutListenKey (params?: {}): Promise; + dapiPrivatePutOrder (params?: {}): Promise; + dapiPrivatePutBatchOrders (params?: {}): Promise; + dapiPrivateDeleteOrder (params?: {}): Promise; + dapiPrivateDeleteAllOpenOrders (params?: {}): Promise; + dapiPrivateDeleteBatchOrders (params?: {}): Promise; + dapiPrivateDeleteListenKey (params?: {}): Promise; + dapiPrivateV2GetLeverageBracket (params?: {}): Promise; + fapiPublicGetPing (params?: {}): Promise; + fapiPublicGetTime (params?: {}): Promise; + fapiPublicGetExchangeInfo (params?: {}): Promise; + fapiPublicGetDepth (params?: {}): Promise; + fapiPublicGetTrades (params?: {}): Promise; + fapiPublicGetHistoricalTrades (params?: {}): Promise; + fapiPublicGetAggTrades (params?: {}): Promise; + fapiPublicGetKlines (params?: {}): Promise; + fapiPublicGetContinuousKlines (params?: {}): Promise; + fapiPublicGetMarkPriceKlines (params?: {}): Promise; + fapiPublicGetIndexPriceKlines (params?: {}): Promise; + fapiPublicGetFundingRate (params?: {}): Promise; + fapiPublicGetFundingInfo (params?: {}): Promise; + fapiPublicGetPremiumIndex (params?: {}): Promise; + fapiPublicGetTicker24hr (params?: {}): Promise; + fapiPublicGetTickerPrice (params?: {}): Promise; + fapiPublicGetTickerBookTicker (params?: {}): Promise; + fapiPublicGetOpenInterest (params?: {}): Promise; + fapiPublicGetIndexInfo (params?: {}): Promise; + fapiPublicGetAssetIndex (params?: {}): Promise; + fapiPublicGetConstituents (params?: {}): Promise; + fapiPublicGetApiTradingStatus (params?: {}): Promise; + fapiPublicGetLvtKlines (params?: {}): Promise; + fapiDataGetDeliveryPrice (params?: {}): Promise; + fapiDataGetOpenInterestHist (params?: {}): Promise; + fapiDataGetTopLongShortAccountRatio (params?: {}): Promise; + fapiDataGetTopLongShortPositionRatio (params?: {}): Promise; + fapiDataGetGlobalLongShortAccountRatio (params?: {}): Promise; + fapiDataGetTakerlongshortRatio (params?: {}): Promise; + fapiDataGetBasis (params?: {}): Promise; + fapiPrivateGetForceOrders (params?: {}): Promise; + fapiPrivateGetAllOrders (params?: {}): Promise; + fapiPrivateGetOpenOrder (params?: {}): Promise; + fapiPrivateGetOpenOrders (params?: {}): Promise; + fapiPrivateGetOrder (params?: {}): Promise; + fapiPrivateGetAccount (params?: {}): Promise; + fapiPrivateGetBalance (params?: {}): Promise; + fapiPrivateGetLeverageBracket (params?: {}): Promise; + fapiPrivateGetPositionMarginHistory (params?: {}): Promise; + fapiPrivateGetPositionRisk (params?: {}): Promise; + fapiPrivateGetPositionSideDual (params?: {}): Promise; + fapiPrivateGetUserTrades (params?: {}): Promise; + fapiPrivateGetIncome (params?: {}): Promise; + fapiPrivateGetCommissionRate (params?: {}): Promise; + fapiPrivateGetApiTradingStatus (params?: {}): Promise; + fapiPrivateGetMultiAssetsMargin (params?: {}): Promise; + fapiPrivateGetApiReferralIfNewUser (params?: {}): Promise; + fapiPrivateGetApiReferralCustomization (params?: {}): Promise; + fapiPrivateGetApiReferralUserCustomization (params?: {}): Promise; + fapiPrivateGetApiReferralTraderNum (params?: {}): Promise; + fapiPrivateGetApiReferralOverview (params?: {}): Promise; + fapiPrivateGetApiReferralTradeVol (params?: {}): Promise; + fapiPrivateGetApiReferralRebateVol (params?: {}): Promise; + fapiPrivateGetApiReferralTraderSummary (params?: {}): Promise; + fapiPrivateGetAdlQuantile (params?: {}): Promise; + fapiPrivateGetPmAccountInfo (params?: {}): Promise; + fapiPrivateGetOrderAmendment (params?: {}): Promise; + fapiPrivateGetIncomeAsyn (params?: {}): Promise; + fapiPrivateGetIncomeAsynId (params?: {}): Promise; + fapiPrivateGetOrderAsyn (params?: {}): Promise; + fapiPrivateGetOrderAsynId (params?: {}): Promise; + fapiPrivateGetTradeAsyn (params?: {}): Promise; + fapiPrivateGetTradeAsynId (params?: {}): Promise; + fapiPrivatePostBatchOrders (params?: {}): Promise; + fapiPrivatePostPositionSideDual (params?: {}): Promise; + fapiPrivatePostPositionMargin (params?: {}): Promise; + fapiPrivatePostMarginType (params?: {}): Promise; + fapiPrivatePostOrder (params?: {}): Promise; + fapiPrivatePostLeverage (params?: {}): Promise; + fapiPrivatePostListenKey (params?: {}): Promise; + fapiPrivatePostCountdownCancelAll (params?: {}): Promise; + fapiPrivatePostMultiAssetsMargin (params?: {}): Promise; + fapiPrivatePostApiReferralCustomization (params?: {}): Promise; + fapiPrivatePostApiReferralUserCustomization (params?: {}): Promise; + fapiPrivatePutListenKey (params?: {}): Promise; + fapiPrivatePutOrder (params?: {}): Promise; + fapiPrivatePutBatchOrders (params?: {}): Promise; + fapiPrivateDeleteBatchOrders (params?: {}): Promise; + fapiPrivateDeleteOrder (params?: {}): Promise; + fapiPrivateDeleteAllOpenOrders (params?: {}): Promise; + fapiPrivateDeleteListenKey (params?: {}): Promise; + fapiPublicV2GetTickerPrice (params?: {}): Promise; + fapiPrivateV2GetAccount (params?: {}): Promise; + fapiPrivateV2GetBalance (params?: {}): Promise; + fapiPrivateV2GetPositionRisk (params?: {}): Promise; + eapiPublicGetPing (params?: {}): Promise; + eapiPublicGetTime (params?: {}): Promise; + eapiPublicGetExchangeInfo (params?: {}): Promise; + eapiPublicGetIndex (params?: {}): Promise; + eapiPublicGetTicker (params?: {}): Promise; + eapiPublicGetMark (params?: {}): Promise; + eapiPublicGetDepth (params?: {}): Promise; + eapiPublicGetKlines (params?: {}): Promise; + eapiPublicGetTrades (params?: {}): Promise; + eapiPublicGetHistoricalTrades (params?: {}): Promise; + eapiPublicGetExerciseHistory (params?: {}): Promise; + eapiPublicGetOpenInterest (params?: {}): Promise; + eapiPrivateGetAccount (params?: {}): Promise; + eapiPrivateGetPosition (params?: {}): Promise; + eapiPrivateGetOpenOrders (params?: {}): Promise; + eapiPrivateGetHistoryOrders (params?: {}): Promise; + eapiPrivateGetUserTrades (params?: {}): Promise; + eapiPrivateGetExerciseRecord (params?: {}): Promise; + eapiPrivateGetBill (params?: {}): Promise; + eapiPrivateGetIncomeAsyn (params?: {}): Promise; + eapiPrivateGetIncomeAsynId (params?: {}): Promise; + eapiPrivateGetMarginAccount (params?: {}): Promise; + eapiPrivateGetMmp (params?: {}): Promise; + eapiPrivateGetCountdownCancelAll (params?: {}): Promise; + eapiPrivateGetOrder (params?: {}): Promise; + eapiPrivatePostOrder (params?: {}): Promise; + eapiPrivatePostBatchOrders (params?: {}): Promise; + eapiPrivatePostListenKey (params?: {}): Promise; + eapiPrivatePostMmpSet (params?: {}): Promise; + eapiPrivatePostMmpReset (params?: {}): Promise; + eapiPrivatePostCountdownCancelAll (params?: {}): Promise; + eapiPrivatePostCountdownCancelAllHeartBeat (params?: {}): Promise; + eapiPrivatePutListenKey (params?: {}): Promise; + eapiPrivateDeleteOrder (params?: {}): Promise; + eapiPrivateDeleteBatchOrders (params?: {}): Promise; + eapiPrivateDeleteAllOpenOrders (params?: {}): Promise; + eapiPrivateDeleteAllOpenOrdersByUnderlying (params?: {}): Promise; + eapiPrivateDeleteListenKey (params?: {}): Promise; + publicGetPing (params?: {}): Promise; + publicGetTime (params?: {}): Promise; + publicGetDepth (params?: {}): Promise; + publicGetTrades (params?: {}): Promise; + publicGetAggTrades (params?: {}): Promise; + publicGetHistoricalTrades (params?: {}): Promise; + publicGetKlines (params?: {}): Promise; + publicGetUiKlines (params?: {}): Promise; + publicGetTicker24hr (params?: {}): Promise; + publicGetTicker (params?: {}): Promise; + publicGetTickerTradingDay (params?: {}): Promise; + publicGetTickerPrice (params?: {}): Promise; + publicGetTickerBookTicker (params?: {}): Promise; + publicGetExchangeInfo (params?: {}): Promise; + publicGetAvgPrice (params?: {}): Promise; + publicPutUserDataStream (params?: {}): Promise; + publicPostUserDataStream (params?: {}): Promise; + publicDeleteUserDataStream (params?: {}): Promise; + privateGetAllOrderList (params?: {}): Promise; + privateGetOpenOrderList (params?: {}): Promise; + privateGetOrderList (params?: {}): Promise; + privateGetOrder (params?: {}): Promise; + privateGetOpenOrders (params?: {}): Promise; + privateGetAllOrders (params?: {}): Promise; + privateGetAccount (params?: {}): Promise; + privateGetMyTrades (params?: {}): Promise; + privateGetRateLimitOrder (params?: {}): Promise; + privateGetMyPreventedMatches (params?: {}): Promise; + privateGetMyAllocations (params?: {}): Promise; + privateGetAccountCommission (params?: {}): Promise; + privatePostOrderOco (params?: {}): Promise; + privatePostSorOrder (params?: {}): Promise; + privatePostSorOrderTest (params?: {}): Promise; + privatePostOrder (params?: {}): Promise; + privatePostOrderCancelReplace (params?: {}): Promise; + privatePostOrderTest (params?: {}): Promise; + privateDeleteOpenOrders (params?: {}): Promise; + privateDeleteOrderList (params?: {}): Promise; + privateDeleteOrder (params?: {}): Promise; + papiGetUmOrder (params?: {}): Promise; + papiGetUmOpenOrder (params?: {}): Promise; + papiGetUmOpenOrders (params?: {}): Promise; + papiGetUmAllOrders (params?: {}): Promise; + papiGetCmOrder (params?: {}): Promise; + papiGetCmOpenOrder (params?: {}): Promise; + papiGetCmOpenOrders (params?: {}): Promise; + papiGetCmAllOrders (params?: {}): Promise; + papiGetUmConditionalOpenOrder (params?: {}): Promise; + papiGetUmConditionalOpenOrders (params?: {}): Promise; + papiGetUmConditionalOrderHistory (params?: {}): Promise; + papiGetUmConditionalAllOrders (params?: {}): Promise; + papiGetCmConditionalOpenOrder (params?: {}): Promise; + papiGetCmConditionalOpenOrders (params?: {}): Promise; + papiGetCmConditionalOrderHistory (params?: {}): Promise; + papiGetCmConditionalAllOrders (params?: {}): Promise; + papiGetMarginOrder (params?: {}): Promise; + papiGetMarginOpenOrders (params?: {}): Promise; + papiGetMarginAllOrders (params?: {}): Promise; + papiGetMarginOrderList (params?: {}): Promise; + papiGetMarginAllOrderList (params?: {}): Promise; + papiGetMarginOpenOrderList (params?: {}): Promise; + papiGetMarginMyTrades (params?: {}): Promise; + papiGetBalance (params?: {}): Promise; + papiGetAccount (params?: {}): Promise; + papiGetMarginMaxBorrowable (params?: {}): Promise; + papiGetMarginMaxWithdraw (params?: {}): Promise; + papiGetUmPositionRisk (params?: {}): Promise; + papiGetCmPositionRisk (params?: {}): Promise; + papiGetUmPositionSideDual (params?: {}): Promise; + papiGetCmPositionSideDual (params?: {}): Promise; + papiGetUmUserTrades (params?: {}): Promise; + papiGetCmUserTrades (params?: {}): Promise; + papiGetUmLeverageBracket (params?: {}): Promise; + papiGetCmLeverageBracket (params?: {}): Promise; + papiGetMarginForceOrders (params?: {}): Promise; + papiGetUmForceOrders (params?: {}): Promise; + papiGetCmForceOrders (params?: {}): Promise; + papiGetUmApiTradingStatus (params?: {}): Promise; + papiGetUmCommissionRate (params?: {}): Promise; + papiGetCmCommissionRate (params?: {}): Promise; + papiGetMarginMarginLoan (params?: {}): Promise; + papiGetMarginRepayLoan (params?: {}): Promise; + papiGetMarginMarginInterestHistory (params?: {}): Promise; + papiGetPortfolioInterestHistory (params?: {}): Promise; + papiGetUmIncome (params?: {}): Promise; + papiGetCmIncome (params?: {}): Promise; + papiGetUmAccount (params?: {}): Promise; + papiGetCmAccount (params?: {}): Promise; + papiGetRepayFuturesSwitch (params?: {}): Promise; + papiGetUmAdlQuantile (params?: {}): Promise; + papiGetCmAdlQuantile (params?: {}): Promise; + papiPostUmOrder (params?: {}): Promise; + papiPostUmConditionalOrder (params?: {}): Promise; + papiPostCmOrder (params?: {}): Promise; + papiPostCmConditionalOrder (params?: {}): Promise; + papiPostMarginOrder (params?: {}): Promise; + papiPostMarginLoan (params?: {}): Promise; + papiPostRepayLoan (params?: {}): Promise; + papiPostMarginOrderOco (params?: {}): Promise; + papiPostUmLeverage (params?: {}): Promise; + papiPostCmLeverage (params?: {}): Promise; + papiPostUmPositionSideDual (params?: {}): Promise; + papiPostCmPositionSideDual (params?: {}): Promise; + papiPostAutoCollection (params?: {}): Promise; + papiPostBnbTransfer (params?: {}): Promise; + papiPostRepayFuturesSwitch (params?: {}): Promise; + papiPostRepayFuturesNegativeBalance (params?: {}): Promise; + papiPostListenKey (params?: {}): Promise; + papiPostAssetCollection (params?: {}): Promise; + papiPutListenKey (params?: {}): Promise; + papiDeleteUmOrder (params?: {}): Promise; + papiDeleteUmConditionalOrder (params?: {}): Promise; + papiDeleteUmAllOpenOrders (params?: {}): Promise; + papiDeleteUmConditionalAllOpenOrders (params?: {}): Promise; + papiDeleteCmOrder (params?: {}): Promise; + papiDeleteCmConditionalOrder (params?: {}): Promise; + papiDeleteCmAllOpenOrders (params?: {}): Promise; + papiDeleteCmConditionalAllOpenOrders (params?: {}): Promise; + papiDeleteMarginOrder (params?: {}): Promise; + papiDeleteMarginAllOpenOrders (params?: {}): Promise; + papiDeleteMarginOrderList (params?: {}): Promise; + papiDeleteListenKey (params?: {}): Promise; +} +abstract class Exchange extends _Exchange {} + +export default Exchange diff --git a/ts/src/youngplatform.ts b/ts/src/youngplatform.ts new file mode 100644 index 0000000000000..707740abbe0a4 --- /dev/null +++ b/ts/src/youngplatform.ts @@ -0,0 +1,9527 @@ + +// --------------------------------------------------------------------------- + +import Exchange from './abstract/youngplatform.js'; +import { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable, OnMaintenance, BadResponse, RequestTimeout, OrderNotFillable, MarginModeAlreadySet } from './base/errors.js'; +import { Precise } from './base/Precise.js'; +import type { Int, OrderSide, Balances, OrderType, Trade, OHLCV, Order, FundingRateHistory, OpenInterest, Liquidation, OrderRequest, Str, Transaction, Ticker, OrderBook, Tickers, Market, Greeks, Strings, Currency, MarketInterface } from './base/types.js'; +import { TRUNCATE, DECIMAL_PLACES } from './base/functions/number.js'; +import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; +import { rsa } from './base/functions/rsa.js'; +import { eddsa } from './base/functions/crypto.js'; +import { ed25519 } from './static_dependencies/noble-curves/ed25519.js'; + +// --------------------------------------------------------------------------- + +/** + * @class youngplatform + * @augments Exchange + */ +export default class youngplatform extends Exchange { + describe () { + return this.deepExtend (super.describe (), { + 'id': 'youngplatform', + 'name': 'Young Platform', + 'countries': [ 'JP', 'MT' ], // Japan, Malta + 'rateLimit': 50, + 'certified': true, + 'pro': true, + // new metainfo2 interface + 'has': { + 'CORS': undefined, + 'spot': true, + 'margin': true, + 'swap': true, + 'future': true, + 'option': true, + 'addMargin': true, + 'borrowCrossMargin': true, + 'borrowIsolatedMargin': true, + 'cancelAllOrders': true, + 'cancelOrder': true, + 'cancelOrders': true, // contract only + 'closeAllPositions': false, + 'closePosition': false, + 'createDepositAddress': false, + 'createOrder': true, + 'createOrders': true, + 'createPostOnlyOrder': true, + 'createReduceOnlyOrder': true, + 'createStopLimitOrder': true, + 'createStopMarketOrder': false, + 'createStopOrder': true, + 'editOrder': true, + 'fetchAccounts': undefined, + 'fetchBalance': true, + 'fetchBidsAsks': true, + 'fetchBorrowInterest': true, + 'fetchBorrowRateHistories': false, + 'fetchBorrowRateHistory': true, + 'fetchCanceledOrders': 'emulated', + 'fetchClosedOrder': false, + 'fetchClosedOrders': 'emulated', + 'fetchCrossBorrowRate': true, + 'fetchCrossBorrowRates': false, + 'fetchCurrencies': true, + 'fetchDeposit': false, + 'fetchDepositAddress': true, + 'fetchDepositAddresses': false, + 'fetchDepositAddressesByNetwork': false, + 'fetchDeposits': true, + 'fetchDepositsWithdrawals': false, + 'fetchDepositWithdrawFee': 'emulated', + 'fetchDepositWithdrawFees': true, + 'fetchFundingHistory': true, + 'fetchFundingRate': true, + 'fetchFundingRateHistory': true, + 'fetchFundingRates': true, + 'fetchGreeks': true, + 'fetchIndexOHLCV': true, + 'fetchIsolatedBorrowRate': false, + 'fetchIsolatedBorrowRates': false, + 'fetchL3OrderBook': false, + 'fetchLedger': true, + 'fetchLeverage': false, + 'fetchLeverageTiers': true, + 'fetchLiquidations': false, + 'fetchMarketLeverageTiers': 'emulated', + 'fetchMarkets': true, + 'fetchMarkOHLCV': true, + 'fetchMyLiquidations': true, + 'fetchMySettlementHistory': true, + 'fetchMyTrades': true, + 'fetchOHLCV': true, + 'fetchOpenInterest': true, + 'fetchOpenInterestHistory': true, + 'fetchOpenOrder': false, + 'fetchOpenOrders': true, + 'fetchOrder': true, + 'fetchOrderBook': true, + 'fetchOrderBooks': false, + 'fetchOrders': true, + 'fetchOrderTrades': true, + 'fetchPosition': true, + 'fetchPositions': true, + 'fetchPositionsRisk': true, + 'fetchPremiumIndexOHLCV': false, + 'fetchSettlementHistory': true, + 'fetchStatus': true, + 'fetchTicker': true, + 'fetchTickers': true, + 'fetchTime': true, + 'fetchTrades': true, + 'fetchTradingFee': true, + 'fetchTradingFees': true, + 'fetchTradingLimits': undefined, + 'fetchTransactionFee': undefined, + 'fetchTransactionFees': true, + 'fetchTransactions': false, + 'fetchTransfers': true, + 'fetchUnderlyingAssets': false, + 'fetchVolatilityHistory': false, + 'fetchWithdrawAddresses': false, + 'fetchWithdrawal': false, + 'fetchWithdrawals': true, + 'fetchWithdrawalWhitelist': false, + 'reduceMargin': true, + 'repayCrossMargin': true, + 'repayIsolatedMargin': true, + 'setLeverage': true, + 'setMargin': false, + 'setMarginMode': true, + 'setPositionMode': true, + 'signIn': false, + 'transfer': true, + 'withdraw': true, + }, + 'timeframes': { + '1s': '1s', // spot only for now + '1m': '1m', + '3m': '3m', + '5m': '5m', + '15m': '15m', + '30m': '30m', + '1h': '1h', + '2h': '2h', + '4h': '4h', + '6h': '6h', + '8h': '8h', + '12h': '12h', + '1d': '1d', + '3d': '3d', + '1w': '1w', + '1M': '1M', + }, + 'urls': { + 'logo': 'https://user-images.githubusercontent.com/1294454/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg', + 'test': { + 'dapiPublic': 'https://testnet.binancefuture.com/dapi/v1', + 'dapiPrivate': 'https://testnet.binancefuture.com/dapi/v1', + 'dapiPrivateV2': 'https://testnet.binancefuture.com/dapi/v2', + 'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1', + 'fapiPublicV2': 'https://testnet.binancefuture.com/fapi/v2', + 'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1', + 'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2', + 'public': 'https://testnet.binance.vision/api/v3', + 'private': 'https://testnet.binance.vision/api/v3', + 'v1': 'https://testnet.binance.vision/api/v1', + }, + 'api': { + 'sapi': 'https://api.binance.com/sapi/v1', + 'sapiV2': 'https://api.binance.com/sapi/v2', + 'sapiV3': 'https://api.binance.com/sapi/v3', + 'sapiV4': 'https://api.binance.com/sapi/v4', + 'dapiPublic': 'https://dapi.binance.com/dapi/v1', + 'dapiPrivate': 'https://dapi.binance.com/dapi/v1', + 'eapiPublic': 'https://eapi.binance.com/eapi/v1', + 'eapiPrivate': 'https://eapi.binance.com/eapi/v1', + 'dapiPrivateV2': 'https://dapi.binance.com/dapi/v2', + 'dapiData': 'https://dapi.binance.com/futures/data', + 'fapiPublic': 'https://fapi.binance.com/fapi/v1', + 'fapiPublicV2': 'https://fapi.binance.com/fapi/v2', + 'fapiPrivate': 'https://fapi.binance.com/fapi/v1', + 'fapiData': 'https://fapi.binance.com/futures/data', + 'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2', + 'public': 'https://api.binance.com/api/v3', + 'private': 'https://api.binance.com/api/v3', + 'v1': 'https://api.binance.com/api/v1', + 'papi': 'https://papi.binance.com/papi/v1', + }, + 'www': 'https://www.binance.com', + 'referral': { + 'url': 'https://accounts.binance.com/en/register?ref=D7YA7CLY', + 'discount': 0.1, + }, + 'doc': [ + 'https://binance-docs.github.io/apidocs/spot/en', + ], + 'api_management': 'https://www.binance.com/en/usercenter/settings/api-management', + 'fees': 'https://www.binance.com/en/fee/schedule', + }, + 'api': { + // the API structure below will need 3-layer apidefs + 'sapi': { + // IP (sapi) request rate limit of 12 000 per minute + // 1 IP (sapi) => cost = 0.1 => (1000 / (50 * 0.1)) * 60 = 12000 + // 10 IP (sapi) => cost = 1 + // UID (sapi) request rate limit of 180 000 per minute + // 1 UID (sapi) => cost = 0.006667 => (1000 / (50 * 0.006667)) * 60 = 180000 + 'get': { + 'system/status': 0.1, + // these endpoints require this.apiKey + 'accountSnapshot': 240, // Weight(IP): 2400 => cost = 0.1 * 2400 = 240 + 'margin/asset': 1, // Weight(IP): 10 => cost = 0.1 * 10 = 1 + 'margin/pair': 1, + 'margin/allAssets': 0.1, + 'margin/allPairs': 0.1, + 'margin/priceIndex': 1, + // these endpoints require this.apiKey + this.secret + 'asset/assetDividend': 1, + 'asset/dribblet': 0.1, + 'asset/transfer': 0.1, + 'asset/assetDetail': 0.1, + 'asset/tradeFee': 0.1, + 'asset/ledger-transfer/cloud-mining/queryByPage': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 + 'asset/convert-transfer/queryByPage': 0.033335, + 'asset/wallet/balance': 6, // Weight(IP): 60 => cost = 0.1 * 60 = 6 + 'asset/custody/transfer-history': 6, // Weight(IP): 60 => cost = 0.1 * 60 = 6 + 'margin/loan': 1, + 'margin/repay': 1, + 'margin/account': 1, + 'margin/transfer': 0.1, + 'margin/interestHistory': 0.1, + 'margin/forceLiquidationRec': 0.1, + 'margin/order': 1, + 'margin/openOrders': 1, + 'margin/allOrders': 20, // Weight(IP): 200 => cost = 0.1 * 200 = 20 + 'margin/myTrades': 1, + 'margin/maxBorrowable': 5, // Weight(IP): 50 => cost = 0.1 * 50 = 5 + 'margin/maxTransferable': 5, + 'margin/tradeCoeff': 1, + 'margin/isolated/transfer': 0.1, + 'margin/isolated/account': 1, + 'margin/isolated/pair': 1, + 'margin/isolated/allPairs': 1, + 'margin/isolated/accountLimit': 0.1, + 'margin/interestRateHistory': 0.1, + 'margin/orderList': 1, + 'margin/allOrderList': 20, // Weight(IP): 200 => cost = 0.1 * 200 = 20 + 'margin/openOrderList': 1, + 'margin/crossMarginData': { 'cost': 0.1, 'noCoin': 0.5 }, + 'margin/isolatedMarginData': { 'cost': 0.1, 'noCoin': 1 }, + 'margin/isolatedMarginTier': 0.1, + 'margin/rateLimit/order': 2, + 'margin/dribblet': 0.1, + 'margin/dust': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20 + 'margin/crossMarginCollateralRatio': 10, + 'margin/exchange-small-liability': 0.6667, + 'margin/exchange-small-liability-history': 0.6667, + 'margin/next-hourly-interest-rate': 0.6667, + 'margin/capital-flow': 10, // Weight(IP): 100 => cost = 0.1 * 100 = 10 + 'margin/delist-schedule': 10, // Weight(IP): 100 => cost = 0.1 * 100 = 10 + 'margin/available-inventory': 0.3334, // Weight(UID): 50 => cost = 0.006667 * 50 = 0.3334 + 'margin/leverageBracket': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'loan/vip/loanable/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/vip/collateral/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/vip/request/data': 2.6668, // Weight(UID): 400 => cost = 0.006667 * 400 = 2.6668 + 'loan/vip/request/interestRate': 2.6668, // Weight(UID): 400 => cost = 0.006667 * 400 = 2.6668 + 'loan/income': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 + 'loan/ongoing/orders': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/ltv/adjustment/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/borrow/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/repay/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/loanable/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/collateral/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/repay/collateral/rate': 600, // Weight(IP): 6000 => cost = 0.1 * 6000 = 600 + 'loan/flexible/ongoing/orders': 30, // Weight(IP): 300 => cost = 0.1 * 300 = 30 + 'loan/flexible/borrow/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/flexible/repay/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/flexible/ltv/adjustment/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/flexible/loanable/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/flexible/collateral/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/vip/ongoing/orders': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/vip/repay/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 + 'loan/vip/collateral/account': 600, // Weight(IP): 6000 => cost = 0.1 * 6000 = 600 + 'fiat/orders': 600.03, // Weight(UID): 90000 => cost = 0.006667 * 90000 = 600.03 + 'fiat/payments': 0.1, + 'futures/transfer': 1, + 'futures/histDataLink': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'rebate/taxQuery': 80.004, // Weight(UID): 12000 => cost = 0.006667 * 12000 = 80.004 + // https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi + 'capital/config/getall': 1, // get networks for withdrawing USDT ERC20 vs USDT Omni + 'capital/deposit/address': 1, + 'capital/deposit/address/list': 1, + 'capital/deposit/hisrec': 0.1, + 'capital/deposit/subAddress': 0.1, + 'capital/deposit/subHisrec': 0.1, + 'capital/withdraw/history': 1800, // Weight(IP): 18000 => cost = 0.1 * 18000 = 1800 + 'capital/contract/convertible-coins': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 + 'convert/tradeFlow': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'convert/exchangeInfo': 50, + 'convert/assetInfo': 10, + 'convert/orderStatus': 0.6667, + 'account/status': 0.1, + 'account/apiTradingStatus': 0.1, + 'account/apiRestrictions/ipRestriction': 0.1, + 'bnbBurn': 0.1, + 'sub-account/futures/account': 1, + 'sub-account/futures/accountSummary': 0.1, + 'sub-account/futures/positionRisk': 1, + 'sub-account/futures/internalTransfer': 0.1, + 'sub-account/list': 0.1, + 'sub-account/margin/account': 1, + 'sub-account/margin/accountSummary': 1, + 'sub-account/spotSummary': 0.1, + 'sub-account/status': 1, + 'sub-account/sub/transfer/history': 0.1, + 'sub-account/transfer/subUserHistory': 0.1, + 'sub-account/universalTransfer': 0.1, + 'sub-account/apiRestrictions/ipRestriction/thirdPartyList': 1, + 'sub-account/transaction-statistics': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 + 'sub-account/subAccountApi/ipRestriction': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'managed-subaccount/asset': 0.1, + 'managed-subaccount/accountSnapshot': 240, + 'managed-subaccount/queryTransLogForInvestor': 0.1, + 'managed-subaccount/queryTransLogForTradeParent': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 + 'managed-subaccount/fetch-future-asset': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 + 'managed-subaccount/marginAsset': 0.1, + 'managed-subaccount/info': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 + 'managed-subaccount/deposit/address': 0.006667, // Weight(UID): 1 => cost = 0.006667 * 1 = 0.006667 + 'managed-subaccount/query-trans-log': 0.40002, + // lending endpoints + 'lending/daily/product/list': 0.1, + 'lending/daily/userLeftQuota': 0.1, + 'lending/daily/userRedemptionQuota': 0.1, + 'lending/daily/token/position': 0.1, + 'lending/union/account': 0.1, + 'lending/union/purchaseRecord': 0.1, + 'lending/union/redemptionRecord': 0.1, + 'lending/union/interestHistory': 0.1, + 'lending/project/list': 0.1, + 'lending/project/position/list': 0.1, + // mining endpoints + 'mining/pub/algoList': 0.1, + 'mining/pub/coinList': 0.1, + 'mining/worker/detail': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5 + 'mining/worker/list': 0.5, + 'mining/payment/list': 0.5, + 'mining/statistics/user/status': 0.5, + 'mining/statistics/user/list': 0.5, + 'mining/payment/uid': 0.5, + // liquid swap endpoints + 'bswap/pools': 0.1, + 'bswap/liquidity': { 'cost': 0.1, 'noPoolId': 1 }, + 'bswap/liquidityOps': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'bswap/quote': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 + 'bswap/swap': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'bswap/poolConfigure': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 + 'bswap/addLiquidityPreview': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 + 'bswap/removeLiquidityPreview': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 + 'bswap/unclaimedRewards': 6.667, // Weight(UID): 1000 => cost = 0.006667 * 1000 = 6.667 + 'bswap/claimedHistory': 6.667, // Weight(UID): 1000 => cost = 0.006667 * 1000 = 6.667 + // leveraged token endpoints + 'blvt/tokenInfo': 0.1, + 'blvt/subscribe/record': 0.1, + 'blvt/redeem/record': 0.1, + 'blvt/userLimit': 0.1, + // broker api TODO (NOT IN DOCS) + 'apiReferral/ifNewUser': 1, + 'apiReferral/customization': 1, + 'apiReferral/userCustomization': 1, + 'apiReferral/rebate/recentRecord': 1, + 'apiReferral/rebate/historicalRecord': 1, + 'apiReferral/kickback/recentRecord': 1, + 'apiReferral/kickback/historicalRecord': 1, + // brokerage API TODO https://binance-docs.github.io/Brokerage-API/General/ does not state ratelimits + 'broker/subAccountApi': 1, + 'broker/subAccount': 1, + 'broker/subAccountApi/commission/futures': 1, + 'broker/subAccountApi/commission/coinFutures': 1, + 'broker/info': 1, + 'broker/transfer': 1, + 'broker/transfer/futures': 1, + 'broker/rebate/recentRecord': 1, + 'broker/rebate/historicalRecord': 1, + 'broker/subAccount/bnbBurn/status': 1, + 'broker/subAccount/depositHist': 1, + 'broker/subAccount/spotSummary': 1, + 'broker/subAccount/marginSummary': 1, + 'broker/subAccount/futuresSummary': 1, + 'broker/rebate/futures/recentRecord': 1, + 'broker/subAccountApi/ipRestriction': 1, + 'broker/universalTransfer': 1, + // v2 not supported yet + // GET /sapi/v2/broker/subAccount/futuresSummary + 'account/apiRestrictions': 0.1, + // c2c / p2p + 'c2c/orderMatch/listUserOrderHistory': 0.1, + // nft endpoints + 'nft/history/transactions': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'nft/history/deposit': 20.001, + 'nft/history/withdraw': 20.001, + 'nft/user/getAsset': 20.001, + 'pay/transactions': 20.001, + 'giftcard/verify': 0.1, + 'giftcard/cryptography/rsa-public-key': 0.1, + 'giftcard/buyCode/token-limit': 0.1, + 'algo/spot/openOrders': 0.1, + 'algo/spot/historicalOrders': 0.1, + 'algo/spot/subOrders': 0.1, + 'algo/futures/openOrders': 0.1, + 'algo/futures/historicalOrders': 0.1, + 'algo/futures/subOrders': 0.1, + 'portfolio/account': 0.1, + 'portfolio/collateralRate': 5, + 'portfolio/pmLoan': 3.3335, + 'portfolio/interest-history': 0.6667, + 'portfolio/asset-index-price': 0.1, + 'portfolio/repay-futures-switch': 3, // Weight(IP): 30 => cost = 0.1 * 30 = 3 + 'portfolio/margin-asset-leverage': 5, // Weight(IP): 50 => cost = 0.1 * 50 = 5 + // staking + 'staking/productList': 0.1, + 'staking/position': 0.1, + 'staking/stakingRecord': 0.1, + 'staking/personalLeftQuota': 0.1, + 'lending/auto-invest/target-asset/list': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/target-asset/roi/list': 0.1, + 'lending/auto-invest/all/asset': 0.1, + 'lending/auto-invest/source-asset/list': 0.1, + 'lending/auto-invest/plan/list': 0.1, + 'lending/auto-invest/plan/id': 0.1, + 'lending/auto-invest/history/list': 0.1, + 'lending/auto-invest/index/info': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/index/user-summary': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/one-off/status': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/redeem/history': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/rebalance/history': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + // simple earn + 'simple-earn/flexible/list': 15, + 'simple-earn/locked/list': 15, + 'simple-earn/flexible/personalLeftQuota': 15, + 'simple-earn/locked/personalLeftQuota': 15, + 'simple-earn/flexible/subscriptionPreview': 15, + 'simple-earn/locked/subscriptionPreview': 15, + 'simple-earn/flexible/history/rateHistory': 15, + 'simple-earn/flexible/position': 15, + 'simple-earn/locked/position': 15, + 'simple-earn/account': 15, + 'simple-earn/flexible/history/subscriptionRecord': 15, + 'simple-earn/locked/history/subscriptionRecord': 15, + 'simple-earn/flexible/history/redemptionRecord': 15, + 'simple-earn/locked/history/redemptionRecord': 15, + 'simple-earn/flexible/history/rewardsRecord': 15, + 'simple-earn/locked/history/rewardsRecord': 15, + 'simple-earn/flexible/history/collateralRecord': 0.1, + }, + 'post': { + 'asset/dust': 0.06667, // Weight(UID): 10 => cost = 0.006667 * 10 = 0.06667 + 'asset/dust-btc': 0.1, + 'asset/transfer': 6.0003, // Weight(UID): 900 => cost = 0.006667 * 900 = 6.0003 + 'asset/get-funding-asset': 0.1, + 'asset/convert-transfer': 0.033335, + 'account/disableFastWithdrawSwitch': 0.1, + 'account/enableFastWithdrawSwitch': 0.1, + // 'account/apiRestrictions/ipRestriction': 1, discontinued + // 'account/apiRestrictions/ipRestriction/ipList': 1, discontinued + 'capital/withdraw/apply': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 + 'capital/contract/convertible-coins': 4.0002, + 'capital/deposit/credit-apply': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'margin/transfer': 4.0002, + 'margin/loan': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'margin/repay': 20.001, + 'margin/order': 0.040002, // Weight(UID): 6 => cost = 0.006667 * 6 = 0.040002 + 'margin/order/oco': 0.040002, + 'margin/dust': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + 'margin/exchange-small-liability': 20.001, + // 'margin/isolated/create': 1, discontinued + 'margin/isolated/transfer': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 + 'margin/isolated/account': 2.0001, // Weight(UID): 300 => cost = 0.006667 * 300 = 2.0001 + 'margin/max-leverage': 300, // Weight(IP): 3000 => cost = 0.1 * 3000 = 300 + 'bnbBurn': 0.1, + 'sub-account/virtualSubAccount': 0.1, + 'sub-account/margin/transfer': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 + 'sub-account/margin/enable': 0.1, + 'sub-account/futures/enable': 0.1, + 'sub-account/futures/transfer': 0.1, + 'sub-account/futures/internalTransfer': 0.1, + 'sub-account/transfer/subToSub': 0.1, + 'sub-account/transfer/subToMaster': 0.1, + 'sub-account/universalTransfer': 0.1, + 'sub-account/options/enable': 0.1, + 'managed-subaccount/deposit': 0.1, + 'managed-subaccount/withdraw': 0.1, + 'userDataStream': 0.1, + 'userDataStream/isolated': 0.1, + 'futures/transfer': 0.1, + // lending + 'lending/customizedFixed/purchase': 0.1, + 'lending/daily/purchase': 0.1, + 'lending/daily/redeem': 0.1, + // liquid swap endpoints + 'bswap/liquidityAdd': 60, // Weight(UID): 1000 + (Additional: 1 request every 3 seconds = 0.333 requests per second) => cost = ( 1000 / rateLimit ) / 0.333 = 60.0000006 + 'bswap/liquidityRemove': 60, // Weight(UID): 1000 + (Additional: 1 request every three seconds) + 'bswap/swap': 60, // Weight(UID): 1000 + (Additional: 1 request every three seconds) + 'bswap/claimRewards': 6.667, // Weight(UID): 1000 => cost = 0.006667 * 1000 = 6.667 + // leveraged token endpoints + 'blvt/subscribe': 0.1, + 'blvt/redeem': 0.1, + // brokerage API TODO: NO MENTION OF RATELIMITS IN BROKERAGE DOCS + 'apiReferral/customization': 1, + 'apiReferral/userCustomization': 1, + 'apiReferral/rebate/historicalRecord': 1, + 'apiReferral/kickback/historicalRecord': 1, + 'broker/subAccount': 1, + 'broker/subAccount/margin': 1, + 'broker/subAccount/futures': 1, + 'broker/subAccountApi': 1, + 'broker/subAccountApi/permission': 1, + 'broker/subAccountApi/commission': 1, + 'broker/subAccountApi/commission/futures': 1, + 'broker/subAccountApi/commission/coinFutures': 1, + 'broker/transfer': 1, + 'broker/transfer/futures': 1, + 'broker/rebate/historicalRecord': 1, + 'broker/subAccount/bnbBurn/spot': 1, + 'broker/subAccount/bnbBurn/marginInterest': 1, + 'broker/subAccount/blvt': 1, + 'broker/subAccountApi/ipRestriction': 1, + 'broker/subAccountApi/ipRestriction/ipList': 1, + 'broker/universalTransfer': 1, + 'broker/subAccountApi/permission/universalTransfer': 1, + 'broker/subAccountApi/permission/vanillaOptions': 1, + // + 'giftcard/createCode': 0.1, + 'giftcard/redeemCode': 0.1, + 'giftcard/buyCode': 0.1, + 'algo/spot/newOrderTwap': 20.001, + 'algo/futures/newOrderVp': 20.001, + 'algo/futures/newOrderTwap': 20.001, + // staking + 'staking/purchase': 0.1, + 'staking/redeem': 0.1, + 'staking/setAutoStaking': 0.1, + 'portfolio/repay': 20.001, + 'loan/vip/renew': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 + 'loan/vip/borrow': 40.002, + 'loan/borrow': 40.002, + 'loan/repay': 40.002, + 'loan/adjust/ltv': 40.002, + 'loan/customize/margin_call': 40.002, + 'loan/flexible/borrow': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 + 'loan/flexible/repay': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 + 'loan/flexible/adjust/ltv': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 + 'loan/vip/repay': 40.002, + 'convert/getQuote': 1.3334, // Weight(UID): 200 => cost = 0.006667 * 200 = 1.3334 + 'convert/acceptQuote': 3.3335, // Weight(UID): 500 => cost = 0.006667 * 500 = 3.3335 + 'portfolio/auto-collection': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 + 'portfolio/asset-collection': 6, // Weight(IP): 60 => cost = 0.1 * 60 = 6 + 'portfolio/bnb-transfer': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 + 'portfolio/repay-futures-switch': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 + 'portfolio/repay-futures-negative-balance': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 + 'lending/auto-invest/plan/add': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/plan/edit': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/plan/edit-status': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/one-off': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + 'lending/auto-invest/redeem': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 + // simple earn + 'simple-earn/flexible/subscribe': 0.1, + 'simple-earn/locked/subscribe': 0.1, + 'simple-earn/flexible/redeem': 0.1, + 'simple-earn/locked/redeem': 0.1, + 'simple-earn/flexible/setAutoSubscribe': 15, + 'simple-earn/locked/setAutoSubscribe': 15, + }, + 'put': { + 'userDataStream': 0.1, + 'userDataStream/isolated': 0.1, + }, + 'delete': { + // 'account/apiRestrictions/ipRestriction/ipList': 1, discontinued + 'margin/openOrders': 0.1, + 'margin/order': 0.006667, // Weight(UID): 1 => cost = 0.006667 + 'margin/orderList': 0.006667, + 'margin/isolated/account': 2.0001, // Weight(UID): 300 => cost = 0.006667 * 300 = 2.0001 + 'userDataStream': 0.1, + 'userDataStream/isolated': 0.1, + // brokerage API TODO NO MENTION OF RATELIMIT IN BROKERAGE DOCS + 'broker/subAccountApi': 1, + 'broker/subAccountApi/ipRestriction/ipList': 1, + 'algo/spot/order': 0.1, + 'algo/futures/order': 0.1, + 'sub-account/subAccountApi/ipRestriction/ipList': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + }, + }, + 'sapiV2': { + 'get': { + 'sub-account/futures/account': 0.1, + 'sub-account/futures/accountSummary': 1, + 'sub-account/futures/positionRisk': 0.1, + }, + 'post': { + 'sub-account/subAccountApi/ipRestriction': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 + }, + }, + 'sapiV3': { + 'get': { + 'sub-account/assets': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 + }, + 'post': { + 'asset/getUserAsset': 0.5, + }, + }, + 'sapiV4': { + 'get': { + 'sub-account/assets': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 + }, + }, + 'dapiPublic': { + 'get': { + 'ping': 1, + 'time': 1, + 'exchangeInfo': 1, + 'depth': { 'cost': 2, 'byLimit': [ [ 50, 2 ], [ 100, 5 ], [ 500, 10 ], [ 1000, 20 ] ] }, + 'trades': 5, + 'historicalTrades': 20, + 'aggTrades': 20, + 'premiumIndex': 10, + 'fundingRate': 1, + 'klines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'continuousKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'indexPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'markPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'premiumIndexKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'ticker/24hr': { 'cost': 1, 'noSymbol': 40 }, + 'ticker/price': { 'cost': 1, 'noSymbol': 2 }, + 'ticker/bookTicker': { 'cost': 2, 'noSymbol': 5 }, + 'constituents': 2, + 'openInterest': 1, + }, + }, + 'dapiData': { + 'get': { + 'delivery-price': 1, + 'openInterestHist': 1, + 'topLongShortAccountRatio': 1, + 'topLongShortPositionRatio': 1, + 'globalLongShortAccountRatio': 1, + 'takerBuySellVol': 1, + 'basis': 1, + }, + }, + 'dapiPrivate': { + 'get': { + 'positionSide/dual': 30, + 'orderAmendment': 1, + 'order': 1, + 'openOrder': 1, + 'openOrders': { 'cost': 1, 'noSymbol': 5 }, + 'allOrders': { 'cost': 20, 'noSymbol': 40 }, + 'balance': 1, + 'account': 5, + 'positionMargin/history': 1, + 'positionRisk': 1, + 'userTrades': { 'cost': 20, 'noSymbol': 40 }, + 'income': 20, + 'leverageBracket': 1, + 'forceOrders': { 'cost': 20, 'noSymbol': 50 }, + 'adlQuantile': 5, + 'commissionRate': 20, + 'income/asyn': 5, + 'income/asyn/id': 5, + 'pmExchangeInfo': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5 + 'pmAccountInfo': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5 + }, + 'post': { + 'positionSide/dual': 1, + 'order': 4, + 'batchOrders': 5, + 'countdownCancelAll': 10, + 'leverage': 1, + 'marginType': 1, + 'positionMargin': 1, + 'listenKey': 1, + }, + 'put': { + 'listenKey': 1, + 'order': 1, + 'batchOrders': 5, + }, + 'delete': { + 'order': 1, + 'allOpenOrders': 1, + 'batchOrders': 5, + 'listenKey': 1, + }, + }, + 'dapiPrivateV2': { + 'get': { + 'leverageBracket': 1, + }, + }, + 'fapiPublic': { + 'get': { + 'ping': 1, + 'time': 1, + 'exchangeInfo': 1, + 'depth': { 'cost': 2, 'byLimit': [ [ 50, 2 ], [ 100, 5 ], [ 500, 10 ], [ 1000, 20 ] ] }, + 'trades': 5, + 'historicalTrades': 20, + 'aggTrades': 20, + 'klines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'continuousKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'markPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'indexPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, + 'fundingRate': 1, + 'fundingInfo': 1, + 'premiumIndex': 1, + 'ticker/24hr': { 'cost': 1, 'noSymbol': 40 }, + 'ticker/price': { 'cost': 1, 'noSymbol': 2 }, + 'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 }, + 'openInterest': 1, + 'indexInfo': 1, + 'assetIndex': { 'cost': 1, 'noSymbol': 10 }, + 'constituents': 2, + 'apiTradingStatus': { 'cost': 1, 'noSymbol': 10 }, + 'lvtKlines': 1, + }, + }, + 'fapiData': { + 'get': { + 'delivery-price': 1, + 'openInterestHist': 1, + 'topLongShortAccountRatio': 1, + 'topLongShortPositionRatio': 1, + 'globalLongShortAccountRatio': 1, + 'takerlongshortRatio': 1, + 'basis': 1, + }, + }, + 'fapiPrivate': { + 'get': { + 'forceOrders': { 'cost': 20, 'noSymbol': 50 }, + 'allOrders': 5, + 'openOrder': 1, + 'openOrders': 1, + 'order': 1, + 'account': 5, + 'balance': 5, + 'leverageBracket': 1, + 'positionMargin/history': 1, + 'positionRisk': 5, + 'positionSide/dual': 30, + 'userTrades': 5, + 'income': 30, + 'commissionRate': 20, + 'apiTradingStatus': 1, + 'multiAssetsMargin': 30, + // broker endpoints + 'apiReferral/ifNewUser': 1, + 'apiReferral/customization': 1, + 'apiReferral/userCustomization': 1, + 'apiReferral/traderNum': 1, + 'apiReferral/overview': 1, + 'apiReferral/tradeVol': 1, + 'apiReferral/rebateVol': 1, + 'apiReferral/traderSummary': 1, + 'adlQuantile': 5, + 'pmAccountInfo': 5, + 'orderAmendment': 1, + 'income/asyn': 1000, + 'income/asyn/id': 10, + 'order/asyn': 1000, + 'order/asyn/id': 10, + 'trade/asyn': 1000, + 'trade/asyn/id': 10, + }, + 'post': { + 'batchOrders': 5, + 'positionSide/dual': 1, + 'positionMargin': 1, + 'marginType': 1, + 'order': 4, + 'leverage': 1, + 'listenKey': 1, + 'countdownCancelAll': 10, + 'multiAssetsMargin': 1, + // broker endpoints + 'apiReferral/customization': 1, + 'apiReferral/userCustomization': 1, + }, + 'put': { + 'listenKey': 1, + 'order': 1, + 'batchOrders': 5, + }, + 'delete': { + 'batchOrders': 1, + 'order': 1, + 'allOpenOrders': 1, + 'listenKey': 1, + }, + }, + 'fapiPublicV2': { + 'get': { + 'ticker/price': 0, + }, + }, + 'fapiPrivateV2': { + 'get': { + 'account': 1, + 'balance': 1, + 'positionRisk': 1, + }, + }, + 'eapiPublic': { + 'get': { + 'ping': 1, + 'time': 1, + 'exchangeInfo': 1, + 'index': 1, + 'ticker': 5, + 'mark': 5, + 'depth': 1, + 'klines': 1, + 'trades': 5, + 'historicalTrades': 20, + 'exerciseHistory': 3, + 'openInterest': 3, + }, + }, + 'eapiPrivate': { + 'get': { + 'account': 3, + 'position': 5, + 'openOrders': { 'cost': 1, 'noSymbol': 40 }, + 'historyOrders': 3, + 'userTrades': 5, + 'exerciseRecord': 5, + 'bill': 1, + 'income/asyn': 5, + 'income/asyn/id': 5, + 'marginAccount': 3, + 'mmp': 1, + 'countdownCancelAll': 1, + 'order': 1, + }, + 'post': { + 'order': 1, + 'batchOrders': 5, + 'listenKey': 1, + 'mmpSet': 1, + 'mmpReset': 1, + 'countdownCancelAll': 1, + 'countdownCancelAllHeartBeat': 10, + }, + 'put': { + 'listenKey': 1, + }, + 'delete': { + 'order': 1, + 'batchOrders': 1, + 'allOpenOrders': 1, + 'allOpenOrdersByUnderlying': 1, + 'listenKey': 1, + }, + }, + 'public': { + // IP (api) request rate limit of 6000 per minute + // 1 IP (api) => cost = 0.2 => (1000 / (50 * 0.2)) * 60 = 6000 + 'get': { + 'ping': 0.2, // Weight(IP): 1 => cost = 0.2 * 1 = 0.2 + 'time': 0.2, + 'depth': { 'cost': 1, 'byLimit': [ [ 100, 1 ], [ 500, 5 ], [ 1000, 10 ], [ 5000, 50 ] ] }, + 'trades': 2, // Weight(IP): 10 => cost = 0.2 * 10 = 2 + 'aggTrades': 0.4, + 'historicalTrades': 2, // Weight(IP): 10 => cost = 0.2 * 10 = 2 + 'klines': 0.4, + 'uiKlines': 0.4, + 'ticker/24hr': { 'cost': 0.4, 'noSymbol': 16 }, + 'ticker': { 'cost': 0.4, 'noSymbol': 16 }, + 'ticker/tradingDay': 0.8, + 'ticker/price': { 'cost': 0.4, 'noSymbol': 0.8 }, + 'ticker/bookTicker': { 'cost': 0.4, 'noSymbol': 0.8 }, + 'exchangeInfo': 4, // Weight(IP): 20 => cost = 0.2 * 20 = 4 + 'avgPrice': 0.4, + }, + 'put': { + 'userDataStream': 0.4, + }, + 'post': { + 'userDataStream': 0.4, + }, + 'delete': { + 'userDataStream': 0.4, + }, + }, + 'private': { + 'get': { + 'allOrderList': 4, // oco Weight(IP): 20 => cost = 0.2 * 20 = 4 + 'openOrderList': 1.2, // oco Weight(IP): 6 => cost = 0.2 * 6 = 1.2 + 'orderList': 0.8, // oco + 'order': 0.8, + 'openOrders': { 'cost': 1.2, 'noSymbol': 16 }, + 'allOrders': 4, + 'account': 4, + 'myTrades': 4, + 'rateLimit/order': 8, // Weight(IP): 40 => cost = 0.2 * 40 = 8 + 'myPreventedMatches': 4, // Weight(IP): 20 => cost = 0.2 * 20 = 4 + 'myAllocations': 4, + 'account/commission': 4, + }, + 'post': { + 'order/oco': 0.2, + 'sor/order': 0.2, + 'sor/order/test': 0.2, + 'order': 0.2, + 'order/cancelReplace': 0.2, + 'order/test': 0.2, + }, + 'delete': { + 'openOrders': 0.2, + 'orderList': 0.2, // oco + 'order': 0.2, + }, + }, + 'papi': { + 'get': { + 'um/order': 1, // 1 + 'um/openOrder': 1, // 1 + 'um/openOrders': 1, // 1 + 'um/allOrders': 5, // 5 + 'cm/order': 1, // 1 + 'cm/openOrder': 1, // 1 + 'cm/openOrders': 1, // 1 + 'cm/allOrders': 20, // 20 + 'um/conditional/openOrder': 1, + 'um/conditional/openOrders': 40, + 'um/conditional/orderHistory': 1, + 'um/conditional/allOrders': 40, + 'cm/conditional/openOrder': 1, + 'cm/conditional/openOrders': 40, + 'cm/conditional/orderHistory': 1, + 'cm/conditional/allOrders': 40, + 'margin/order': 5, + 'margin/openOrders': 5, + 'margin/allOrders': 100, + 'margin/orderList': 5, + 'margin/allOrderList': 100, + 'margin/openOrderList': 5, + 'margin/myTrades': 5, + 'balance': 20, // 20 + 'account': 20, // 20 + 'margin/maxBorrowable': 5, // 5 + 'margin/maxWithdraw': 5, // 5 + 'um/positionRisk': 5, // 5 + 'cm/positionRisk': 1, // 1 + 'um/positionSide/dual': 30, // 30 + 'cm/positionSide/dual': 30, // 30 + 'um/userTrades': 5, // 5 + 'cm/userTrades': 20, // 20 + 'um/leverageBracket': 1, // 1 + 'cm/leverageBracket': 1, // 1 + 'margin/forceOrders': 1, // 1 + 'um/forceOrders': 20, // 20 + 'cm/forceOrders': 20, // 20 + 'um/apiTradingStatus': 1, // 1 + 'um/commissionRate': 20, // 20 + 'cm/commissionRate': 20, // 20 + 'margin/marginLoan': 10, + 'margin/repayLoan': 10, + 'margin/marginInterestHistory': 1, + 'portfolio/interest-history': 50, // 50 + 'um/income': 30, + 'cm/income': 30, + 'um/account': 5, + 'cm/account': 5, + 'repay-futures-switch': 3, // Weight(IP): 30 => cost = 0.1 * 30 = 3 + 'um/adlQuantile': 5, + 'cm/adlQuantile': 5, + }, + 'post': { + 'um/order': 1, // 0 + 'um/conditional/order': 1, + 'cm/order': 1, // 0 + 'cm/conditional/order': 1, + 'margin/order': 0.0133, // Weight(UID): 2 => cost = 0.006667 * 2 = 0.013334 + 'marginLoan': 0.1333, // Weight(UID): 20 => cost = 0.006667 * 20 = 0.13334 + 'repayLoan': 0.1333, // Weight(UID): 20 => cost = 0.006667 * 20 = 0.13334 + 'margin/order/oco': 0.0400, // Weight(UID): 6 => cost = 0.006667 * 6 = 0.040002 + 'um/leverage': 1, // 1 + 'cm/leverage': 1, // 1 + 'um/positionSide/dual': 1, // 1 + 'cm/positionSide/dual': 1, // 1 + 'auto-collection': 0.6667, // Weight(UID): 100 => cost = 0.006667 * 100 = 0.6667 + 'bnb-transfer': 0.6667, // Weight(UID): 100 => cost = 0.006667 * 100 = 0.6667 + 'repay-futures-switch': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 + 'repay-futures-negative-balance': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 + 'listenKey': 1, // 1 + 'asset-collection': 3, + }, + 'put': { + 'listenKey': 1, // 1 + }, + 'delete': { + 'um/order': 1, // 1 + 'um/conditional/order': 1, + 'um/allOpenOrders': 1, // 1 + 'um/conditional/allOpenOrders': 1, + 'cm/order': 1, // 1 + 'cm/conditional/order': 1, + 'cm/allOpenOrders': 1, // 1 + 'cm/conditional/allOpenOrders': 1, + 'margin/order': 1, // Weight(IP): 10 => cost = 0.1 * 10 = 1 + 'margin/allOpenOrders': 5, // 5 + 'margin/orderList': 2, // 2 + 'listenKey': 1, // 1 + }, + }, + }, + 'fees': { + 'trading': { + 'feeSide': 'get', + 'tierBased': false, + 'percentage': true, + 'taker': this.parseNumber ('0.001'), + 'maker': this.parseNumber ('0.001'), + }, + 'linear': { + 'trading': { + 'feeSide': 'quote', + 'tierBased': true, + 'percentage': true, + 'taker': this.parseNumber ('0.000400'), + 'maker': this.parseNumber ('0.000200'), + 'tiers': { + 'taker': [ + [ this.parseNumber ('0'), this.parseNumber ('0.000400') ], + [ this.parseNumber ('250'), this.parseNumber ('0.000400') ], + [ this.parseNumber ('2500'), this.parseNumber ('0.000350') ], + [ this.parseNumber ('7500'), this.parseNumber ('0.000320') ], + [ this.parseNumber ('22500'), this.parseNumber ('0.000300') ], + [ this.parseNumber ('50000'), this.parseNumber ('0.000270') ], + [ this.parseNumber ('100000'), this.parseNumber ('0.000250') ], + [ this.parseNumber ('200000'), this.parseNumber ('0.000220') ], + [ this.parseNumber ('400000'), this.parseNumber ('0.000200') ], + [ this.parseNumber ('750000'), this.parseNumber ('0.000170') ], + ], + 'maker': [ + [ this.parseNumber ('0'), this.parseNumber ('0.000200') ], + [ this.parseNumber ('250'), this.parseNumber ('0.000160') ], + [ this.parseNumber ('2500'), this.parseNumber ('0.000140') ], + [ this.parseNumber ('7500'), this.parseNumber ('0.000120') ], + [ this.parseNumber ('22500'), this.parseNumber ('0.000100') ], + [ this.parseNumber ('50000'), this.parseNumber ('0.000080') ], + [ this.parseNumber ('100000'), this.parseNumber ('0.000060') ], + [ this.parseNumber ('200000'), this.parseNumber ('0.000040') ], + [ this.parseNumber ('400000'), this.parseNumber ('0.000020') ], + [ this.parseNumber ('750000'), this.parseNumber ('0') ], + ], + }, + }, + }, + 'inverse': { + 'trading': { + 'feeSide': 'base', + 'tierBased': true, + 'percentage': true, + 'taker': this.parseNumber ('0.000500'), + 'maker': this.parseNumber ('0.000100'), + 'tiers': { + 'taker': [ + [ this.parseNumber ('0'), this.parseNumber ('0.000500') ], + [ this.parseNumber ('250'), this.parseNumber ('0.000450') ], + [ this.parseNumber ('2500'), this.parseNumber ('0.000400') ], + [ this.parseNumber ('7500'), this.parseNumber ('0.000300') ], + [ this.parseNumber ('22500'), this.parseNumber ('0.000250') ], + [ this.parseNumber ('50000'), this.parseNumber ('0.000240') ], + [ this.parseNumber ('100000'), this.parseNumber ('0.000240') ], + [ this.parseNumber ('200000'), this.parseNumber ('0.000240') ], + [ this.parseNumber ('400000'), this.parseNumber ('0.000240') ], + [ this.parseNumber ('750000'), this.parseNumber ('0.000240') ], + ], + 'maker': [ + [ this.parseNumber ('0'), this.parseNumber ('0.000100') ], + [ this.parseNumber ('250'), this.parseNumber ('0.000080') ], + [ this.parseNumber ('2500'), this.parseNumber ('0.000050') ], + [ this.parseNumber ('7500'), this.parseNumber ('0.0000030') ], + [ this.parseNumber ('22500'), this.parseNumber ('0') ], + [ this.parseNumber ('50000'), this.parseNumber ('-0.000050') ], + [ this.parseNumber ('100000'), this.parseNumber ('-0.000060') ], + [ this.parseNumber ('200000'), this.parseNumber ('-0.000070') ], + [ this.parseNumber ('400000'), this.parseNumber ('-0.000080') ], + [ this.parseNumber ('750000'), this.parseNumber ('-0.000090') ], + ], + }, + }, + }, + 'option': {}, + }, + 'commonCurrencies': { + 'BCC': 'BCC', // kept for backward-compatibility https://github.com/ccxt/ccxt/issues/4848 + 'YOYO': 'YOYOW', + }, + 'precisionMode': DECIMAL_PLACES, + // exchange-specific options + 'options': { + 'sandboxMode': false, + 'fetchMarkets': [ + 'spot', // allows CORS in browsers + 'linear', // allows CORS in browsers + 'inverse', // allows CORS in browsers + // 'option', // does not allow CORS, enable outside of the browser only + ], + 'fetchCurrencies': true, // this is a private call and it requires API keys + // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades, eapiPublicGetTrades + 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel + 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery', 'option' + 'defaultSubType': undefined, // 'linear', 'inverse' + 'hasAlreadyAuthenticatedSuccessfully': false, + 'warnOnFetchOpenOrdersWithoutSymbol': true, + // not an error + // https://github.com/ccxt/ccxt/issues/11268 + // https://github.com/ccxt/ccxt/pull/11624 + // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request + // binanceusdm + 'throwMarginModeAlreadySet': false, + 'fetchPositions': 'positionRisk', // or 'account' or 'option' + 'recvWindow': 10 * 1000, // 10 sec + 'timeDifference': 0, // the difference between system clock and Binance clock + 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation + 'newOrderRespType': { + 'market': 'FULL', // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills + 'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit) + }, + 'quoteOrderQty': true, // whether market orders support amounts in quote currency + 'broker': { + 'spot': 'x-R4BD3S82', + 'margin': 'x-R4BD3S82', + 'future': 'x-xcKtGhcu', + 'delivery': 'x-xcKtGhcu', + 'swap': 'x-xcKtGhcu', + 'option': 'x-xcKtGhcu', + }, + 'accountsByType': { + 'main': 'MAIN', + 'spot': 'MAIN', + 'funding': 'FUNDING', + 'margin': 'MARGIN', + 'cross': 'MARGIN', + 'future': 'UMFUTURE', // backwards compatibility + 'delivery': 'CMFUTURE', // backwards compatbility + 'linear': 'UMFUTURE', + 'inverse': 'CMFUTURE', + 'option': 'OPTION', + }, + 'accountsById': { + 'MAIN': 'spot', + 'FUNDING': 'funding', + 'MARGIN': 'margin', + 'UMFUTURE': 'linear', + 'CMFUTURE': 'inverse', + 'OPTION': 'option', + }, + 'networks': { + 'ERC20': 'ETH', + 'TRC20': 'TRX', + 'BEP2': 'BNB', + 'BEP20': 'BSC', + 'OMNI': 'OMNI', + 'EOS': 'EOS', + 'SPL': 'SOL', + }, + // keeping this object for backward-compatibility + 'reverseNetworks': { + 'tronscan.org': 'TRC20', + 'etherscan.io': 'ERC20', + 'bscscan.com': 'BSC', + 'explorer.binance.org': 'BEP2', + 'bithomp.com': 'XRP', + 'bloks.io': 'EOS', + 'stellar.expert': 'XLM', + 'blockchair.com/bitcoin': 'BTC', + 'blockchair.com/bitcoin-cash': 'BCH', + 'blockchair.com/ecash': 'XEC', + 'explorer.litecoin.net': 'LTC', + 'explorer.avax.network': 'AVAX', + 'solscan.io': 'SOL', + 'polkadot.subscan.io': 'DOT', + 'dashboard.internetcomputer.org': 'ICP', + 'explorer.chiliz.com': 'CHZ', + 'cardanoscan.io': 'ADA', + 'mainnet.theoan.com': 'AION', + 'algoexplorer.io': 'ALGO', + 'explorer.ambrosus.com': 'AMB', + 'viewblock.io/zilliqa': 'ZIL', + 'viewblock.io/arweave': 'AR', + 'explorer.ark.io': 'ARK', + 'atomscan.com': 'ATOM', + 'www.mintscan.io': 'CTK', + 'explorer.bitcoindiamond.org': 'BCD', + 'btgexplorer.com': 'BTG', + 'bts.ai': 'BTS', + 'explorer.celo.org': 'CELO', + 'explorer.nervos.org': 'CKB', + 'cerebro.cortexlabs.ai': 'CTXC', + 'chainz.cryptoid.info': 'VIA', + 'explorer.dcrdata.org': 'DCR', + 'digiexplorer.info': 'DGB', + 'dock.subscan.io': 'DOCK', + 'dogechain.info': 'DOGE', + 'explorer.elrond.com': 'EGLD', + 'blockscout.com': 'ETC', + 'explore-fetchhub.fetch.ai': 'FET', + 'filfox.info': 'FIL', + 'fio.bloks.io': 'FIO', + 'explorer.firo.org': 'FIRO', + 'neoscan.io': 'NEO', + 'ftmscan.com': 'FTM', + 'explorer.gochain.io': 'GO', + 'block.gxb.io': 'GXS', + 'hash-hash.info': 'HBAR', + 'www.hiveblockexplorer.com': 'HIVE', + 'explorer.helium.com': 'HNT', + 'tracker.icon.foundation': 'ICX', + 'www.iostabc.com': 'IOST', + 'explorer.iota.org': 'IOTA', + 'iotexscan.io': 'IOTX', + 'irishub.iobscan.io': 'IRIS', + 'kava.mintscan.io': 'KAVA', + 'scope.klaytn.com': 'KLAY', + 'kmdexplorer.io': 'KMD', + 'kusama.subscan.io': 'KSM', + 'explorer.lto.network': 'LTO', + 'polygonscan.com': 'POLYGON', + 'explorer.ont.io': 'ONT', + 'minaexplorer.com': 'MINA', + 'nanolooker.com': 'NANO', + 'explorer.nebulas.io': 'NAS', + 'explorer.nbs.plus': 'NBS', + 'explorer.nebl.io': 'NEBL', + 'nulscan.io': 'NULS', + 'nxscan.com': 'NXS', + 'explorer.harmony.one': 'ONE', + 'explorer.poa.network': 'POA', + 'qtum.info': 'QTUM', + 'explorer.rsk.co': 'RSK', + 'www.oasisscan.com': 'ROSE', + 'ravencoin.network': 'RVN', + 'sc.tokenview.com': 'SC', + 'secretnodes.com': 'SCRT', + 'explorer.skycoin.com': 'SKY', + 'steemscan.com': 'STEEM', + 'explorer.stacks.co': 'STX', + 'www.thetascan.io': 'THETA', + 'scan.tomochain.com': 'TOMO', + 'explore.vechain.org': 'VET', + 'explorer.vite.net': 'VITE', + 'www.wanscan.org': 'WAN', + 'wavesexplorer.com': 'WAVES', + 'wax.eosx.io': 'WAXP', + 'waltonchain.pro': 'WTC', + 'chain.nem.ninja': 'XEM', + 'verge-blockchain.info': 'XVG', + 'explorer.yoyow.org': 'YOYOW', + 'explorer.zcha.in': 'ZEC', + 'explorer.zensystem.io': 'ZEN', + }, + 'networksById': { + 'tronscan.org': 'TRC20', + 'etherscan.io': 'ERC20', + 'bscscan.com': 'BSC', + 'explorer.binance.org': 'BEP2', + 'bithomp.com': 'XRP', + 'bloks.io': 'EOS', + 'stellar.expert': 'XLM', + 'blockchair.com/bitcoin': 'BTC', + 'blockchair.com/bitcoin-cash': 'BCH', + 'blockchair.com/ecash': 'XEC', + 'explorer.litecoin.net': 'LTC', + 'explorer.avax.network': 'AVAX', + 'solscan.io': 'SOL', + 'polkadot.subscan.io': 'DOT', + 'dashboard.internetcomputer.org': 'ICP', + 'explorer.chiliz.com': 'CHZ', + 'cardanoscan.io': 'ADA', + 'mainnet.theoan.com': 'AION', + 'algoexplorer.io': 'ALGO', + 'explorer.ambrosus.com': 'AMB', + 'viewblock.io/zilliqa': 'ZIL', + 'viewblock.io/arweave': 'AR', + 'explorer.ark.io': 'ARK', + 'atomscan.com': 'ATOM', + 'www.mintscan.io': 'CTK', + 'explorer.bitcoindiamond.org': 'BCD', + 'btgexplorer.com': 'BTG', + 'bts.ai': 'BTS', + 'explorer.celo.org': 'CELO', + 'explorer.nervos.org': 'CKB', + 'cerebro.cortexlabs.ai': 'CTXC', + 'chainz.cryptoid.info': 'VIA', + 'explorer.dcrdata.org': 'DCR', + 'digiexplorer.info': 'DGB', + 'dock.subscan.io': 'DOCK', + 'dogechain.info': 'DOGE', + 'explorer.elrond.com': 'EGLD', + 'blockscout.com': 'ETC', + 'explore-fetchhub.fetch.ai': 'FET', + 'filfox.info': 'FIL', + 'fio.bloks.io': 'FIO', + 'explorer.firo.org': 'FIRO', + 'neoscan.io': 'NEO', + 'ftmscan.com': 'FTM', + 'explorer.gochain.io': 'GO', + 'block.gxb.io': 'GXS', + 'hash-hash.info': 'HBAR', + 'www.hiveblockexplorer.com': 'HIVE', + 'explorer.helium.com': 'HNT', + 'tracker.icon.foundation': 'ICX', + 'www.iostabc.com': 'IOST', + 'explorer.iota.org': 'IOTA', + 'iotexscan.io': 'IOTX', + 'irishub.iobscan.io': 'IRIS', + 'kava.mintscan.io': 'KAVA', + 'scope.klaytn.com': 'KLAY', + 'kmdexplorer.io': 'KMD', + 'kusama.subscan.io': 'KSM', + 'explorer.lto.network': 'LTO', + 'polygonscan.com': 'POLYGON', + 'explorer.ont.io': 'ONT', + 'minaexplorer.com': 'MINA', + 'nanolooker.com': 'NANO', + 'explorer.nebulas.io': 'NAS', + 'explorer.nbs.plus': 'NBS', + 'explorer.nebl.io': 'NEBL', + 'nulscan.io': 'NULS', + 'nxscan.com': 'NXS', + 'explorer.harmony.one': 'ONE', + 'explorer.poa.network': 'POA', + 'qtum.info': 'QTUM', + 'explorer.rsk.co': 'RSK', + 'www.oasisscan.com': 'ROSE', + 'ravencoin.network': 'RVN', + 'sc.tokenview.com': 'SC', + 'secretnodes.com': 'SCRT', + 'explorer.skycoin.com': 'SKY', + 'steemscan.com': 'STEEM', + 'explorer.stacks.co': 'STX', + 'www.thetascan.io': 'THETA', + 'scan.tomochain.com': 'TOMO', + 'explore.vechain.org': 'VET', + 'explorer.vite.net': 'VITE', + 'www.wanscan.org': 'WAN', + 'wavesexplorer.com': 'WAVES', + 'wax.eosx.io': 'WAXP', + 'waltonchain.pro': 'WTC', + 'chain.nem.ninja': 'XEM', + 'verge-blockchain.info': 'XVG', + 'explorer.yoyow.org': 'YOYOW', + 'explorer.zcha.in': 'ZEC', + 'explorer.zensystem.io': 'ZEN', + }, + 'impliedNetworks': { + 'ETH': { 'ERC20': 'ETH' }, + 'TRX': { 'TRC20': 'TRX' }, + }, + 'legalMoney': { + 'MXN': true, + 'UGX': true, + 'SEK': true, + 'CHF': true, + 'VND': true, + 'AED': true, + 'DKK': true, + 'KZT': true, + 'HUF': true, + 'PEN': true, + 'PHP': true, + 'USD': true, + 'TRY': true, + 'EUR': true, + 'NGN': true, + 'PLN': true, + 'BRL': true, + 'ZAR': true, + 'KES': true, + 'ARS': true, + 'RUB': true, + 'AUD': true, + 'NOK': true, + 'CZK': true, + 'GBP': true, + 'UAH': true, + 'GHS': true, + 'HKD': true, + 'CAD': true, + 'INR': true, + 'JPY': true, + 'NZD': true, + }, + 'legalMoneyCurrenciesById': { + 'BUSD': 'USD', + }, + }, + // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2 + 'exceptions': { + 'exact': { + 'System is under maintenance.': OnMaintenance, // {"code":1,"msg":"System is under maintenance."} + 'System abnormality': ExchangeError, // {"code":-1000,"msg":"System abnormality"} + 'You are not authorized to execute this request.': PermissionDenied, // {"msg":"You are not authorized to execute this request."} + 'API key does not exist': AuthenticationError, + 'Order would trigger immediately.': OrderImmediatelyFillable, + 'Stop price would trigger immediately.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Stop price would trigger immediately."} + 'Order would immediately match and take.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Order would immediately match and take."} + 'Account has insufficient balance for requested action.': InsufficientFunds, + 'Rest API trading is not enabled.': ExchangeNotAvailable, + 'This account may not place or cancel orders.': ExchangeNotAvailable, + "You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false} + 'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."} + 'Too many requests. Please try again later.': DDoSProtection, // {"msg":"Too many requests. Please try again later.","success":false} + 'This action is disabled on this account.': AccountSuspended, // {"code":-2011,"msg":"This action is disabled on this account."} + 'Limit orders require GTC for this phase.': BadRequest, + 'This order type is not possible in this trading phase.': BadRequest, + 'This type of sub-account exceeds the maximum number limit': BadRequest, // {"code":-9000,"msg":"This type of sub-account exceeds the maximum number limit"} + 'This symbol is restricted for this account.': PermissionDenied, + 'This symbol is not permitted for this account.': PermissionDenied, // {"code":-2010,"msg":"This symbol is not permitted for this account."} + '-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."} + '-1001': ExchangeNotAvailable, // {"code":-1001,"msg":"'Internal error; unable to process your request. Please try again.'"} + '-1002': AuthenticationError, // {"code":-1002,"msg":"'You are not authorized to execute this request.'"} + '-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."} + '-1004': DDoSProtection, // {"code":-1004,"msg":"Server is busy, please wait and try again"} + '-1005': PermissionDenied, // {"code":-1005,"msg":"No such IP has been white listed"} + '-1006': BadResponse, // {"code":-1006,"msg":"An unexpected response was received from the message bus. Execution status unknown."} + '-1007': RequestTimeout, // {"code":-1007,"msg":"Timeout waiting for response from backend server. Send status unknown; execution status unknown."} + '-1010': BadResponse, // {"code":-1010,"msg":"ERROR_MSG_RECEIVED."} + '-1011': PermissionDenied, // {"code":-1011,"msg":"This IP cannot access this route."} + '-1013': InvalidOrder, // {"code":-1013,"msg":"createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL"} + '-1014': InvalidOrder, // {"code":-1014,"msg":"Unsupported order combination."} + '-1015': RateLimitExceeded, // {"code":-1015,"msg":"'Too many new orders; current limit is %s orders per %s.'"} + '-1016': ExchangeNotAvailable, // {"code":-1016,"msg":"'This service is no longer available.',"} + '-1020': BadRequest, // {"code":-1020,"msg":"'This operation is not supported.'"} + '-1021': InvalidNonce, // {"code":-1021,"msg":"'your time is ahead of server'"} + '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."} + '-1023': BadRequest, // {"code":-1023,"msg":"Start time is greater than end time."} + '-1099': AuthenticationError, // {"code":-1099,"msg":"Not found, authenticated, or authorized"} + '-1100': BadRequest, // {"code":-1100,"msg":"createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'"} + '-1101': BadRequest, // {"code":-1101,"msg":"Too many parameters; expected %s and received %s."} + '-1102': BadRequest, // {"code":-1102,"msg":"Param %s or %s must be sent, but both were empty"} + '-1103': BadRequest, // {"code":-1103,"msg":"An unknown parameter was sent."} + '-1104': BadRequest, // {"code":-1104,"msg":"Not all sent parameters were read, read 8 parameters but was sent 9"} + '-1105': BadRequest, // {"code":-1105,"msg":"Parameter %s was empty."} + '-1106': BadRequest, // {"code":-1106,"msg":"Parameter %s sent when not required."} + '-1108': BadRequest, // {"code":-1108,"msg":"Invalid asset."} + '-1109': AuthenticationError, // {"code":-1109,"msg":"Invalid account."} + '-1110': BadRequest, // {"code":-1110,"msg":"Invalid symbolType."} + '-1111': BadRequest, // {"code":-1111,"msg":"Precision is over the maximum defined for this asset."} + '-1112': InvalidOrder, // {"code":-1112,"msg":"No orders on book for symbol."} + '-1113': BadRequest, // {"code":-1113,"msg":"Withdrawal amount must be negative."} + '-1114': BadRequest, // {"code":-1114,"msg":"TimeInForce parameter sent when not required."} + '-1115': BadRequest, // {"code":-1115,"msg":"Invalid timeInForce."} + '-1116': BadRequest, // {"code":-1116,"msg":"Invalid orderType."} + '-1117': BadRequest, // {"code":-1117,"msg":"Invalid side."} + '-1118': BadRequest, // {"code":-1118,"msg":"New client order ID was empty."} + '-1119': BadRequest, // {"code":-1119,"msg":"Original client order ID was empty."} + '-1120': BadRequest, // {"code":-1120,"msg":"Invalid interval."} + '-1121': BadSymbol, // {"code":-1121,"msg":"Invalid symbol."} + '-1125': AuthenticationError, // {"code":-1125,"msg":"This listenKey does not exist."} + '-1127': BadRequest, // {"code":-1127,"msg":"More than %s hours between startTime and endTime."} + '-1128': BadRequest, // {"code":-1128,"msg":"{"code":-1128,"msg":"Combination of optional parameters invalid."}"} + '-1130': BadRequest, // {"code":-1130,"msg":"Data sent for paramter %s is not valid."} + '-1131': BadRequest, // {"code":-1131,"msg":"recvWindow must be less than 60000"} + '-1135': BadRequest, // This error code will occur if a parameter requiring a JSON object is invalid. + '-1136': BadRequest, // {"code":-1136,"msg":"Invalid newOrderRespType"} + '-2008': AuthenticationError, // {"code":-2008,"msg":"Invalid Api-Key ID."} + '-2010': ExchangeError, // {"code":-2010,"msg":"generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc..."} + '-2011': OrderNotFound, // {"code":-2011,"msg":"cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'"} + '-2013': OrderNotFound, // {"code":-2013,"msg":"fetchOrder (1, 'BTC/USDT') -> 'Order does not exist'"} + '-2014': AuthenticationError, // {"code":-2014,"msg":"API-key format invalid."} + '-2015': AuthenticationError, // {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} + '-2016': BadRequest, // {"code":-2016,"msg":"No trading window could be found for the symbol. Try ticker/24hrs instead."} + '-2018': InsufficientFunds, // {"code":-2018,"msg":"Balance is insufficient"} + '-2019': InsufficientFunds, // {"code":-2019,"msg":"Margin is insufficient."} + '-2020': OrderNotFillable, // {"code":-2020,"msg":"Unable to fill."} + '-2021': OrderImmediatelyFillable, // {"code":-2021,"msg":"Order would immediately trigger."} + '-2022': InvalidOrder, // {"code":-2022,"msg":"ReduceOnly Order is rejected."} + '-2023': InsufficientFunds, // {"code":-2023,"msg":"User in liquidation mode now."} + '-2024': InsufficientFunds, // {"code":-2024,"msg":"Position is not sufficient."} + '-2025': InvalidOrder, // {"code":-2025,"msg":"Reach max open order limit."} + '-2026': InvalidOrder, // {"code":-2026,"msg":"This OrderType is not supported when reduceOnly."} + '-2027': InvalidOrder, // {"code":-2027,"msg":"Exceeded the maximum allowable position at current leverage."} + '-2028': InsufficientFunds, // {"code":-2028,"msg":"Leverage is smaller than permitted: insufficient margin balance"} + '-3000': ExchangeError, // {"code":-3000,"msg":"Internal server error."} + '-3001': AuthenticationError, // {"code":-3001,"msg":"Please enable 2FA first."} + '-3002': BadSymbol, // {"code":-3002,"msg":"We don't have this asset."} + '-3003': BadRequest, // {"code":-3003,"msg":"Margin account does not exist."} + '-3004': ExchangeError, // {"code":-3004,"msg":"Trade not allowed."} + '-3005': InsufficientFunds, // {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."} + '-3006': InsufficientFunds, // {"code":-3006,"msg":"Your borrow amount has exceed maximum borrow amount."} + '-3007': ExchangeError, // {"code":-3007,"msg":"You have pending transaction, please try again later.."} + '-3008': InsufficientFunds, // {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."} + '-3009': BadRequest, // {"code":-3009,"msg":"This asset are not allowed to transfer into margin account currently."} + '-3010': BadRequest, // {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."} + '-3011': BadRequest, // {"code":-3011,"msg":"Your input date is invalid."} + '-3012': InsufficientFunds, // {"code":-3012,"msg":"Borrow is banned for this asset."} + '-3013': BadRequest, // {"code":-3013,"msg":"Borrow amount less than minimum borrow amount."} + '-3014': AccountSuspended, // {"code":-3014,"msg":"Borrow is banned for this account."} + '-3015': BadRequest, // {"code":-3015,"msg":"Repay amount exceeds borrow amount."} + '-3016': BadRequest, // {"code":-3016,"msg":"Repay amount less than minimum repay amount."} + '-3017': ExchangeError, // {"code":-3017,"msg":"This asset are not allowed to transfer into margin account currently."} + '-3018': AccountSuspended, // {"code":-3018,"msg":"Transferring in has been banned for this account."} + '-3019': AccountSuspended, // {"code":-3019,"msg":"Transferring out has been banned for this account."} + '-3020': InsufficientFunds, // {"code":-3020,"msg":"Transfer out amount exceeds max amount."} + '-3021': BadRequest, // {"code":-3021,"msg":"Margin account are not allowed to trade this trading pair."} + '-3022': AccountSuspended, // {"code":-3022,"msg":"You account's trading is banned."} + '-3023': BadRequest, // {"code":-3023,"msg":"You can't transfer out/place order under current margin level."} + '-3024': ExchangeError, // {"code":-3024,"msg":"The unpaid debt is too small after this repayment."} + '-3025': BadRequest, // {"code":-3025,"msg":"Your input date is invalid."} + '-3026': BadRequest, // {"code":-3026,"msg":"Your input param is invalid."} + '-3027': BadSymbol, // {"code":-3027,"msg":"Not a valid margin asset."} + '-3028': BadSymbol, // {"code":-3028,"msg":"Not a valid margin pair."} + '-3029': ExchangeError, // {"code":-3029,"msg":"Transfer failed."} + '-3036': AccountSuspended, // {"code":-3036,"msg":"This account is not allowed to repay."} + '-3037': ExchangeError, // {"code":-3037,"msg":"PNL is clearing. Wait a second."} + '-3038': BadRequest, // {"code":-3038,"msg":"Listen key not found."} + '-3041': InsufficientFunds, // {"code":-3041,"msg":"Balance is not enough"} + '-3042': BadRequest, // {"code":-3042,"msg":"PriceIndex not available for this margin pair."} + '-3043': BadRequest, // {"code":-3043,"msg":"Transferring in not allowed."} + '-3044': DDoSProtection, // {"code":-3044,"msg":"System busy."} + '-3045': ExchangeError, // {"code":-3045,"msg":"The system doesn't have enough asset now."} + '-3999': ExchangeError, // {"code":-3999,"msg":"This function is only available for invited users."} + '-4001': BadRequest, // {"code":-4001 ,"msg":"Invalid operation."} + '-4002': BadRequest, // {"code":-4002 ,"msg":"Invalid get."} + '-4003': BadRequest, // {"code":-4003 ,"msg":"Your input email is invalid."} + '-4004': AuthenticationError, // {"code":-4004,"msg":"You don't login or auth."} + '-4005': RateLimitExceeded, // {"code":-4005 ,"msg":"Too many new requests."} + '-4006': BadRequest, // {"code":-4006 ,"msg":"Support main account only."} + '-4007': BadRequest, // {"code":-4007 ,"msg":"Address validation is not passed."} + '-4008': BadRequest, // {"code":-4008 ,"msg":"Address tag validation is not passed."} + '-4010': BadRequest, // {"code":-4010 ,"msg":"White list mail has been confirmed."} // [TODO] possible bug: it should probably be "has not been confirmed" + '-4011': BadRequest, // {"code":-4011 ,"msg":"White list mail is invalid."} + '-4012': BadRequest, // {"code":-4012 ,"msg":"White list is not opened."} + '-4013': AuthenticationError, // {"code":-4013 ,"msg":"2FA is not opened."} + '-4014': PermissionDenied, // {"code":-4014 ,"msg":"Withdraw is not allowed within 2 min login."} + '-4015': ExchangeError, // {"code":-4015 ,"msg":"Withdraw is limited."} + '-4016': PermissionDenied, // {"code":-4016 ,"msg":"Within 24 hours after password modification, withdrawal is prohibited."} | on swap: {"code":-4016,"msg":"Limit price can't be higher than 27330.52."} + '-4017': PermissionDenied, // {"code":-4017 ,"msg":"Within 24 hours after the release of 2FA, withdrawal is prohibited."} + '-4018': BadSymbol, // {"code":-4018,"msg":"We don't have this asset."} + '-4019': BadSymbol, // {"code":-4019,"msg":"Current asset is not open for withdrawal."} + '-4021': BadRequest, // {"code":-4021,"msg":"Asset withdrawal must be an %s multiple of %s."} + '-4022': BadRequest, // {"code":-4022,"msg":"Not less than the minimum pick-up quantity %s."} + '-4023': ExchangeError, // {"code":-4023,"msg":"Within 24 hours, the withdrawal exceeds the maximum amount."} + '-4024': InsufficientFunds, // {"code":-4024,"msg":"You don't have this asset."} + '-4025': InsufficientFunds, // {"code":-4025,"msg":"The number of hold asset is less than zero."} + '-4026': InsufficientFunds, // {"code":-4026,"msg":"You have insufficient balance."} + '-4027': ExchangeError, // {"code":-4027,"msg":"Failed to obtain tranId."} + '-4028': BadRequest, // {"code":-4028,"msg":"The amount of withdrawal must be greater than the Commission."} + '-4029': BadRequest, // {"code":-4029,"msg":"The withdrawal record does not exist."} + '-4030': ExchangeError, // {"code":-4030,"msg":"Confirmation of successful asset withdrawal. [TODO] possible bug in docs"} + '-4031': ExchangeError, // {"code":-4031,"msg":"Cancellation failed."} + '-4032': ExchangeError, // {"code":-4032,"msg":"Withdraw verification exception."} + '-4033': BadRequest, // {"code":-4033,"msg":"Illegal address."} + '-4034': ExchangeError, // {"code":-4034,"msg":"The address is suspected of fake."} + '-4035': PermissionDenied, // {"code":-4035,"msg":"This address is not on the whitelist. Please join and try again."} + '-4036': BadRequest, // {"code":-4036,"msg":"The new address needs to be withdrawn in {0} hours."} + '-4037': ExchangeError, // {"code":-4037,"msg":"Re-sending Mail failed."} + '-4038': ExchangeError, // {"code":-4038,"msg":"Please try again in 5 minutes."} + '-4039': BadRequest, // {"code":-4039,"msg":"The user does not exist."} + '-4040': BadRequest, // {"code":-4040,"msg":"This address not charged."} + '-4041': ExchangeError, // {"code":-4041,"msg":"Please try again in one minute."} + '-4042': ExchangeError, // {"code":-4042,"msg":"This asset cannot get deposit address again."} + '-4043': BadRequest, // {"code":-4043,"msg":"More than 100 recharge addresses were used in 24 hours."} + '-4044': BadRequest, // {"code":-4044,"msg":"This is a blacklist country."} + '-4045': ExchangeError, // {"code":-4045,"msg":"Failure to acquire assets."} + '-4046': AuthenticationError, // {"code":-4046,"msg":"Agreement not confirmed."} + '-4047': BadRequest, // {"code":-4047,"msg":"Time interval must be within 0-90 days"} + '-4054': BadRequest, // {"code":-4054,"msg":"Cannot add position margin: position is 0."} + '-5001': BadRequest, // {"code":-5001,"msg":"Don't allow transfer to micro assets."} + '-5002': InsufficientFunds, // {"code":-5002,"msg":"You have insufficient balance."} + '-5003': InsufficientFunds, // {"code":-5003,"msg":"You don't have this asset."} + '-5004': BadRequest, // {"code":-5004,"msg":"The residual balances of %s have exceeded 0.001BTC, Please re-choose."} + '-5005': InsufficientFunds, // {"code":-5005,"msg":"The residual balances of %s is too low, Please re-choose."} + '-5006': BadRequest, // {"code":-5006,"msg":"Only transfer once in 24 hours."} + '-5007': BadRequest, // {"code":-5007,"msg":"Quantity must be greater than zero."} + '-5008': InsufficientFunds, // {"code":-5008,"msg":"Insufficient amount of returnable assets."} + '-5009': BadRequest, // {"code":-5009,"msg":"Product does not exist."} + '-5010': ExchangeError, // {"code":-5010,"msg":"Asset transfer fail."} + '-5011': BadRequest, // {"code":-5011,"msg":"future account not exists."} + '-5012': ExchangeError, // {"code":-5012,"msg":"Asset transfer is in pending."} + '-5013': InsufficientFunds, // {"code":-5013,"msg":"Asset transfer failed: insufficient balance""} // undocumented + '-5021': BadRequest, // {"code":-5021,"msg":"This parent sub have no relation"} + '-6001': BadRequest, // {"code":-6001,"msg":"Daily product not exists."} + '-6003': BadRequest, // {"code":-6003,"msg":"Product not exist or you don't have permission"} + '-6004': ExchangeError, // {"code":-6004,"msg":"Product not in purchase status"} + '-6005': InvalidOrder, // {"code":-6005,"msg":"Smaller than min purchase limit"} + '-6006': BadRequest, // {"code":-6006,"msg":"Redeem amount error"} + '-6007': BadRequest, // {"code":-6007,"msg":"Not in redeem time"} + '-6008': BadRequest, // {"code":-6008,"msg":"Product not in redeem status"} + '-6009': RateLimitExceeded, // {"code":-6009,"msg":"Request frequency too high"} + '-6011': BadRequest, // {"code":-6011,"msg":"Exceeding the maximum num allowed to purchase per user"} + '-6012': InsufficientFunds, // {"code":-6012,"msg":"Balance not enough"} + '-6013': ExchangeError, // {"code":-6013,"msg":"Purchasing failed"} + '-6014': BadRequest, // {"code":-6014,"msg":"Exceed up-limit allowed to purchased"} + '-6015': BadRequest, // {"code":-6015,"msg":"Empty request body"} + '-6016': BadRequest, // {"code":-6016,"msg":"Parameter err"} + '-6017': BadRequest, // {"code":-6017,"msg":"Not in whitelist"} + '-6018': BadRequest, // {"code":-6018,"msg":"Asset not enough"} + '-6019': AuthenticationError, // {"code":-6019,"msg":"Need confirm"} + '-6020': BadRequest, // {"code":-6020,"msg":"Project not exists"} + '-7001': BadRequest, // {"code":-7001,"msg":"Date range is not supported."} + '-7002': BadRequest, // {"code":-7002,"msg":"Data request type is not supported."} + '-9000': InsufficientFunds, // {"code":-9000,"msg":"user have no avaliable amount"}" + '-10017': BadRequest, // {"code":-10017,"msg":"Repay amount should not be larger than liability."} + '-11008': InsufficientFunds, // {"code":-11008,"msg":"Exceeding the account's maximum borrowable limit."} // undocumented + '-12014': RateLimitExceeded, // {"code":-12014,"msg":"More than 1 request in 3 seconds"} + '-13000': BadRequest, // {"code":-13000,"msg":"Redeption of the token is forbiden now"} + '-13001': BadRequest, // {"code":-13001,"msg":"Exceeds individual 24h redemption limit of the token"} + '-13002': BadRequest, // {"code":-13002,"msg":"Exceeds total 24h redemption limit of the token"} + '-13003': BadRequest, // {"code":-13003,"msg":"Subscription of the token is forbiden now"} + '-13004': BadRequest, // {"code":-13004,"msg":"Exceeds individual 24h subscription limit of the token"} + '-13005': BadRequest, // {"code":-13005,"msg":"Exceeds total 24h subscription limit of the token"} + '-13006': InvalidOrder, // {"code":-13006,"msg":"Subscription amount is too small"} + '-13007': AuthenticationError, // {"code":-13007,"msg":"The Agreement is not signed"} + '-21001': BadRequest, // {"code":-21001,"msg":"USER_IS_NOT_UNIACCOUNT"} + '-21002': BadRequest, // {"code":-21002,"msg":"UNI_ACCOUNT_CANT_TRANSFER_FUTURE"} + '-21003': BadRequest, // {"code":-21003,"msg":"NET_ASSET_MUST_LTE_RATIO"} + '100001003': AuthenticationError, // {"code":100001003,"msg":"Verification failed"} // undocumented + '200003903': AuthenticationError, // {"code":200003903,"msg":"Your identity verification has been rejected. Please complete identity verification again."} + }, + 'broad': { + 'has no operation privilege': PermissionDenied, + 'MAX_POSITION': InvalidOrder, // {"code":-2010,"msg":"Filter failure: MAX_POSITION"} + }, + }, + }); + } + + isInverse (type, subType = undefined): boolean { + if (subType === undefined) { + return type === 'delivery'; + } else { + return subType === 'inverse'; + } + } + + isLinear (type, subType = undefined): boolean { + if (subType === undefined) { + return (type === 'future') || (type === 'swap'); + } else { + return subType === 'linear'; + } + } + + setSandboxMode (enable) { + super.setSandboxMode (enable); + this.options['sandboxMode'] = enable; + } + + convertExpireDate (date) { + // parse YYMMDD to timestamp + const year = date.slice (0, 2); + const month = date.slice (2, 4); + const day = date.slice (4, 6); + const reconstructedDate = '20' + year + '-' + month + '-' + day + 'T00:00:00Z'; + return reconstructedDate; + } + + createExpiredOptionMarket (symbol) { + // support expired option contracts + const settle = 'USDT'; + const optionParts = symbol.split ('-'); + const symbolBase = symbol.split ('/'); + let base = undefined; + if (symbol.indexOf ('/') > -1) { + base = this.safeString (symbolBase, 0); + } else { + base = this.safeString (optionParts, 0); + } + const expiry = this.safeString (optionParts, 1); + const strike = this.safeInteger (optionParts, 2); + const strikeAsString = this.safeString (optionParts, 2); + const optionType = this.safeString (optionParts, 3); + const datetime = this.convertExpireDate (expiry); + const timestamp = this.parse8601 (datetime); + return { + 'id': base + '-' + expiry + '-' + strikeAsString + '-' + optionType, + 'symbol': base + '/' + settle + ':' + settle + '-' + expiry + '-' + strikeAsString + '-' + optionType, + 'base': base, + 'quote': settle, + 'baseId': base, + 'quoteId': settle, + 'active': undefined, + 'type': 'option', + 'linear': undefined, + 'inverse': undefined, + 'spot': false, + 'swap': false, + 'future': false, + 'option': true, + 'margin': false, + 'contract': true, + 'contractSize': undefined, + 'expiry': timestamp, + 'expiryDatetime': datetime, + 'optionType': (optionType === 'C') ? 'call' : 'put', + 'strike': strike, + 'settle': settle, + 'settleId': settle, + 'precision': { + 'amount': undefined, + 'price': undefined, + }, + 'limits': { + 'amount': { + 'min': undefined, + 'max': undefined, + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + }, + 'info': undefined, + } as MarketInterface; + } + + market (symbol) { + if (this.markets === undefined) { + throw new ExchangeError (this.id + ' markets not loaded'); + } + // defaultType has legacy support on binance + let defaultType = this.safeString (this.options, 'defaultType'); + const defaultSubType = this.safeString (this.options, 'defaultSubType'); + const isLegacyLinear = defaultType === 'future'; + const isLegacyInverse = defaultType === 'delivery'; + const isLegacy = isLegacyLinear || isLegacyInverse; + if (typeof symbol === 'string') { + if (symbol in this.markets) { + const market = this.markets[symbol]; + // begin diff + if (isLegacy && market['spot']) { + const settle = isLegacyLinear ? market['quote'] : market['base']; + const futuresSymbol = symbol + ':' + settle; + if (futuresSymbol in this.markets) { + return this.markets[futuresSymbol]; + } + } else { + return market; + } + // end diff + } else if (symbol in this.markets_by_id) { + const markets = this.markets_by_id[symbol]; + // begin diff + if (isLegacyLinear) { + defaultType = 'linear'; + } else if (isLegacyInverse) { + defaultType = 'inverse'; + } else if (defaultType === undefined) { + defaultType = defaultSubType; + } + // end diff + for (let i = 0; i < markets.length; i++) { + const market = markets[i]; + if (market[defaultType]) { + return market; + } + } + return markets[0]; + } else if ((symbol.indexOf ('/') > -1) && (symbol.indexOf (':') < 0)) { + // support legacy symbols + const [ base, quote ] = symbol.split ('/'); + const settle = (quote === 'USD') ? base : quote; + const futuresSymbol = symbol + ':' + settle; + if (futuresSymbol in this.markets) { + return this.markets[futuresSymbol]; + } + } else if ((symbol.indexOf ('-C') > -1) || (symbol.indexOf ('-P') > -1)) { // both exchange-id and unified symbols are supported this way regardless of the defaultType + return this.createExpiredOptionMarket (symbol); + } + } + throw new BadSymbol (this.id + ' does not have market symbol ' + symbol); + } + + safeMarket (marketId = undefined, market = undefined, delimiter = undefined, marketType = undefined) { + const isOption = (marketId !== undefined) && ((marketId.indexOf ('-C') > -1) || (marketId.indexOf ('-P') > -1)); + if (isOption && !(marketId in this.markets_by_id)) { + // handle expired option contracts + return this.createExpiredOptionMarket (marketId); + } + return super.safeMarket (marketId, market, delimiter, marketType); + } + + costToPrecision (symbol, cost) { + return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['quote'], this.precisionMode, this.paddingMode); + } + + currencyToPrecision (code, fee, networkCode = undefined) { + // info is available in currencies only if the user has configured his api keys + if (this.safeValue (this.currencies[code], 'precision') !== undefined) { + return this.decimalToPrecision (fee, TRUNCATE, this.currencies[code]['precision'], this.precisionMode, this.paddingMode); + } else { + return this.numberToString (fee); + } + } + + nonce () { + return this.milliseconds () - this.options['timeDifference']; + } + + async fetchTime (params = {}) { + /** + * @method + * @name binance#fetchTime + * @description fetches the current integer timestamp in milliseconds from the exchange server + * @see https://binance-docs.github.io/apidocs/spot/en/#check-server-time // spot + * @see https://binance-docs.github.io/apidocs/futures/en/#check-server-time // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#check-server-time // future + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {int} the current integer timestamp in milliseconds from the exchange server + */ + const defaultType = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchTime', undefined, params); + let response = undefined; + if (this.isLinear (type, subType)) { + response = await this.fapiPublicGetTime (query); + } else if (this.isInverse (type, subType)) { + response = await this.dapiPublicGetTime (query); + } else { + response = await this.publicGetTime (query); + } + return this.safeInteger (response, 'serverTime'); + } + + async fetchCurrencies (params = {}) { + /** + * @method + * @name binance#fetchCurrencies + * @description fetches all available currencies on an exchange + * @see https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} an associative dictionary of currencies + */ + const fetchCurrenciesEnabled = this.safeValue (this.options, 'fetchCurrencies'); + if (!fetchCurrenciesEnabled) { + return undefined; + } + // this endpoint requires authentication + // while fetchCurrencies is a public API method by design + // therefore we check the keys here + // and fallback to generating the currencies from the markets + if (!this.checkRequiredCredentials (false)) { + return undefined; + } + // sandbox/testnet does not support sapi endpoints + const apiBackup = this.safeValue (this.urls, 'apiBackup'); + if (apiBackup !== undefined) { + return undefined; + } + const response = await this.sapiGetCapitalConfigGetall (params); + const result = {}; + for (let i = 0; i < response.length; i++) { + // + // { + // "coin": "LINK", + // "depositAllEnable": true, + // "withdrawAllEnable": true, + // "name": "ChainLink", + // "free": "0", + // "locked": "0", + // "freeze": "0", + // "withdrawing": "0", + // "ipoing": "0", + // "ipoable": "0", + // "storage": "0", + // "isLegalMoney": false, + // "trading": true, + // "networkList": [ + // { + // "network": "BSC", + // "coin": "LINK", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": false, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": "", + // "withdrawDesc": "", + // "specialTips": "", + // "specialWithdrawTips": "The network you have selected is BSC. Please ensure that the withdrawal address supports the Binance Smart Chain network. You will lose your assets if the chosen platform does not support retrievals.", + // "name": "BNB Smart Chain (BEP20)", + // "resetAddressStatus": false, + // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", + // "addressRule": "", + // "memoRegex": "", + // "withdrawFee": "0.012", + // "withdrawMin": "0.024", + // "withdrawMax": "9999999999.99999999", + // "minConfirm": "15", + // "unLockConfirm": "0", + // "sameAddress": false, + // "estimatedArrivalTime": "5", + // "busy": false, + // "country": "AE,BINANCE_BAHRAIN_BSC" + // }, + // { + // "network": "BNB", + // "coin": "LINK", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": false, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": "", + // "withdrawDesc": "", + // "specialTips": "Both a MEMO and an Address are required to successfully deposit your LINK BEP2 tokens to Binance.", + // "specialWithdrawTips": "", + // "name": "BNB Beacon Chain (BEP2)", + // "resetAddressStatus": false, + // "addressRegex": "^(bnb1)[0-9a-z]{38}$", + // "addressRule": "", + // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", + // "withdrawFee": "0.002", + // "withdrawMin": "0.01", + // "withdrawMax": "10000000000", + // "minConfirm": "1", + // "unLockConfirm": "0", + // "sameAddress": true, + // "estimatedArrivalTime": "5", + // "busy": false, + // "country": "AE,BINANCE_BAHRAIN_BSC" + // }, + // { + // "network": "ETH", + // "coin": "LINK", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": true, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": "", + // "withdrawDesc": "", + // "name": "Ethereum (ERC20)", + // "resetAddressStatus": false, + // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", + // "addressRule": "", + // "memoRegex": "", + // "withdrawFee": "0.55", + // "withdrawMin": "1.1", + // "withdrawMax": "10000000000", + // "minConfirm": "12", + // "unLockConfirm": "0", + // "sameAddress": false, + // "estimatedArrivalTime": "5", + // "busy": false, + // "country": "AE,BINANCE_BAHRAIN_BSC" + // } + // ] + // } + // + const entry = response[i]; + const id = this.safeString (entry, 'coin'); + const name = this.safeString (entry, 'name'); + const code = this.safeCurrencyCode (id); + let minPrecision = undefined; + let isWithdrawEnabled = true; + let isDepositEnabled = true; + const networkList = this.safeValue (entry, 'networkList', []); + const fees = {}; + let fee = undefined; + for (let j = 0; j < networkList.length; j++) { + const networkItem = networkList[j]; + const network = this.safeString (networkItem, 'network'); + // const name = this.safeString (networkItem, 'name'); + const withdrawFee = this.safeNumber (networkItem, 'withdrawFee'); + const depositEnable = this.safeValue (networkItem, 'depositEnable'); + const withdrawEnable = this.safeValue (networkItem, 'withdrawEnable'); + isDepositEnabled = isDepositEnabled || depositEnable; + isWithdrawEnabled = isWithdrawEnabled || withdrawEnable; + fees[network] = withdrawFee; + const isDefault = this.safeValue (networkItem, 'isDefault'); + if (isDefault || (fee === undefined)) { + fee = withdrawFee; + } + const precisionTick = this.safeString (networkItem, 'withdrawIntegerMultiple'); + // avoid zero values, which are mostly from fiat or leveraged tokens : https://github.com/ccxt/ccxt/pull/14902#issuecomment-1271636731 + // so, when there is zero instead of i.e. 0.001, then we skip those cases, because we don't know the precision - it might be because of network is suspended or other reasons + if (!Precise.stringEq (precisionTick, '0')) { + minPrecision = (minPrecision === undefined) ? precisionTick : Precise.stringMin (minPrecision, precisionTick); + } + } + const trading = this.safeValue (entry, 'trading'); + const active = (isWithdrawEnabled && isDepositEnabled && trading); + let maxDecimalPlaces = undefined; + if (minPrecision !== undefined) { + maxDecimalPlaces = parseInt (this.numberToString (this.precisionFromString (minPrecision))); + } + result[code] = { + 'id': id, + 'name': name, + 'code': code, + 'precision': maxDecimalPlaces, + 'info': entry, + 'active': active, + 'deposit': isDepositEnabled, + 'withdraw': isWithdrawEnabled, + 'networks': networkList, + 'fee': fee, + 'fees': fees, + 'limits': this.limits, + }; + } + return result; + } + + async fetchMarkets (params = {}) { + /** + * @method + * @name binance#fetchMarkets + * @description retrieves data on all markets for binance + * @see https://binance-docs.github.io/apidocs/spot/en/#exchange-information // spot + * @see https://binance-docs.github.io/apidocs/futures/en/#exchange-information // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#exchange-information // future + * @see https://binance-docs.github.io/apidocs/voptions/en/#exchange-information // option + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} an array of objects representing market data + */ + const promisesRaw = []; + const rawFetchMarkets = this.safeValue (this.options, 'fetchMarkets', [ 'spot', 'linear', 'inverse' ]); + const sandboxMode = this.safeValue (this.options, 'sandboxMode', false); + const fetchMarkets = []; + for (let i = 0; i < rawFetchMarkets.length; i++) { + const type = rawFetchMarkets[i]; + if (type === 'option' && sandboxMode) { + continue; + } + fetchMarkets.push (type); + } + for (let i = 0; i < fetchMarkets.length; i++) { + const marketType = fetchMarkets[i]; + if (marketType === 'spot') { + promisesRaw.push (this.publicGetExchangeInfo (params)); + } else if (marketType === 'linear') { + promisesRaw.push (this.fapiPublicGetExchangeInfo (params)); + } else if (marketType === 'inverse') { + promisesRaw.push (this.dapiPublicGetExchangeInfo (params)); + } else if (marketType === 'option') { + promisesRaw.push (this.eapiPublicGetExchangeInfo (params)); + } else { + throw new ExchangeError (this.id + ' fetchMarkets() this.options fetchMarkets "' + marketType + '" is not a supported market type'); + } + } + const promises = await Promise.all (promisesRaw); + const spotMarkets = this.safeValue (this.safeValue (promises, 0), 'symbols', []); + const futureMarkets = this.safeValue (this.safeValue (promises, 1), 'symbols', []); + const deliveryMarkets = this.safeValue (this.safeValue (promises, 2), 'symbols', []); + const optionMarkets = this.safeValue (this.safeValue (promises, 3), 'optionSymbols', []); + let markets = spotMarkets; + markets = this.arrayConcat (markets, futureMarkets); + markets = this.arrayConcat (markets, deliveryMarkets); + markets = this.arrayConcat (markets, optionMarkets); + // + // spot / margin + // + // { + // "timezone":"UTC", + // "serverTime":1575416692969, + // "rateLimits":[ + // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200}, + // {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":100}, + // {"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":200000} + // ], + // "exchangeFilters":[], + // "symbols":[ + // { + // "symbol":"ETHBTC", + // "status":"TRADING", + // "baseAsset":"ETH", + // "baseAssetPrecision":8, + // "quoteAsset":"BTC", + // "quotePrecision":8, + // "baseCommissionPrecision":8, + // "quoteCommissionPrecision":8, + // "orderTypes":["LIMIT","LIMIT_MAKER","MARKET","STOP_LOSS_LIMIT","TAKE_PROFIT_LIMIT"], + // "icebergAllowed":true, + // "ocoAllowed":true, + // "quoteOrderQtyMarketAllowed":true, + // "allowTrailingStop":false, + // "isSpotTradingAllowed":true, + // "isMarginTradingAllowed":true, + // "filters":[ + // {"filterType":"PRICE_FILTER","minPrice":"0.00000100","maxPrice":"100000.00000000","tickSize":"0.00000100"}, + // {"filterType":"PERCENT_PRICE","multiplierUp":"5","multiplierDown":"0.2","avgPriceMins":5}, + // {"filterType":"LOT_SIZE","minQty":"0.00100000","maxQty":"100000.00000000","stepSize":"0.00100000"}, + // {"filterType":"MIN_NOTIONAL","minNotional":"0.00010000","applyToMarket":true,"avgPriceMins":5}, + // {"filterType":"ICEBERG_PARTS","limit":10}, + // {"filterType":"MARKET_LOT_SIZE","minQty":"0.00000000","maxQty":"63100.00000000","stepSize":"0.00000000"}, + // {"filterType":"MAX_NUM_ORDERS","maxNumOrders":200}, + // {"filterType":"MAX_NUM_ALGO_ORDERS","maxNumAlgoOrders":5} + // ], + // "permissions":["SPOT","MARGIN"]} + // }, + // ], + // } + // + // futures/usdt-margined (fapi) + // + // { + // "timezone":"UTC", + // "serverTime":1575417244353, + // "rateLimits":[ + // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200}, + // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":1200} + // ], + // "exchangeFilters":[], + // "symbols":[ + // { + // "symbol":"BTCUSDT", + // "status":"TRADING", + // "maintMarginPercent":"2.5000", + // "requiredMarginPercent":"5.0000", + // "baseAsset":"BTC", + // "quoteAsset":"USDT", + // "pricePrecision":2, + // "quantityPrecision":3, + // "baseAssetPrecision":8, + // "quotePrecision":8, + // "filters":[ + // {"minPrice":"0.01","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.01"}, + // {"stepSize":"0.001","filterType":"LOT_SIZE","maxQty":"1000","minQty":"0.001"}, + // {"stepSize":"0.001","filterType":"MARKET_LOT_SIZE","maxQty":"1000","minQty":"0.001"}, + // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, + // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} + // ], + // "orderTypes":["LIMIT","MARKET","STOP"], + // "timeInForce":["GTC","IOC","FOK","GTX"] + // } + // ] + // } + // + // delivery/coin-margined (dapi) + // + // { + // "timezone": "UTC", + // "serverTime": 1597667052958, + // "rateLimits": [ + // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000}, + // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":6000} + // ], + // "exchangeFilters": [], + // "symbols": [ + // { + // "symbol": "BTCUSD_200925", + // "pair": "BTCUSD", + // "contractType": "CURRENT_QUARTER", + // "deliveryDate": 1601020800000, + // "onboardDate": 1590739200000, + // "contractStatus": "TRADING", + // "contractSize": 100, + // "marginAsset": "BTC", + // "maintMarginPercent": "2.5000", + // "requiredMarginPercent": "5.0000", + // "baseAsset": "BTC", + // "quoteAsset": "USD", + // "pricePrecision": 1, + // "quantityPrecision": 0, + // "baseAssetPrecision": 8, + // "quotePrecision": 8, + // "equalQtyPrecision": 4, + // "filters": [ + // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"}, + // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"}, + // {"stepSize":"0","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"}, + // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, + // {"multiplierDown":"0.9500","multiplierUp":"1.0500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} + // ], + // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"], + // "timeInForce": ["GTC","IOC","FOK","GTX"] + // }, + // { + // "symbol": "BTCUSD_PERP", + // "pair": "BTCUSD", + // "contractType": "PERPETUAL", + // "deliveryDate": 4133404800000, + // "onboardDate": 1596006000000, + // "contractStatus": "TRADING", + // "contractSize": 100, + // "marginAsset": "BTC", + // "maintMarginPercent": "2.5000", + // "requiredMarginPercent": "5.0000", + // "baseAsset": "BTC", + // "quoteAsset": "USD", + // "pricePrecision": 1, + // "quantityPrecision": 0, + // "baseAssetPrecision": 8, + // "quotePrecision": 8, + // "equalQtyPrecision": 4, + // "filters": [ + // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"}, + // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"}, + // {"stepSize":"1","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"}, + // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, + // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} + // ], + // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"], + // "timeInForce": ["GTC","IOC","FOK","GTX"] + // } + // ] + // } + // + // options (eapi) + // + // { + // "timezone": "UTC", + // "serverTime": 1675912490405, + // "optionContracts": [ + // { + // "id": 1, + // "baseAsset": "SOL", + // "quoteAsset": "USDT", + // "underlying": "SOLUSDT", + // "settleAsset": "USDT" + // }, + // ... + // ], + // "optionAssets": [ + // {"id":1,"name":"USDT"} + // ], + // "optionSymbols": [ + // { + // "contractId": 3, + // "expiryDate": 1677225600000, + // "filters": [ + // {"filterType":"PRICE_FILTER","minPrice":"724.6","maxPrice":"919.2","tickSize":"0.1"}, + // {"filterType":"LOT_SIZE","minQty":"0.01","maxQty":"1000","stepSize":"0.01"} + // ], + // "id": 2474, + // "symbol": "ETH-230224-800-C", + // "side": "CALL", + // "strikePrice": "800.00000000", + // "underlying": "ETHUSDT", + // "unit": 1, + // "makerFeeRate": "0.00020000", + // "takerFeeRate": "0.00020000", + // "minQty": "0.01", + // "maxQty": "1000", + // "initialMargin": "0.15000000", + // "maintenanceMargin": "0.07500000", + // "minInitialMargin": "0.10000000", + // "minMaintenanceMargin": "0.05000000", + // "priceScale": 1, + // "quantityScale": 2, + // "quoteAsset": "USDT" + // }, + // ... + // ], + // "rateLimits": [ + // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":400}, + // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":100}, + // {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":30} + // ] + // } + // + if (this.options['adjustForTimeDifference']) { + await this.loadTimeDifference (); + } + const result = []; + for (let i = 0; i < markets.length; i++) { + result.push (this.parseMarket (markets[i])); + } + return result; + } + + parseMarket (market): Market { + let swap = false; + let future = false; + let option = false; + const underlying = this.safeString (market, 'underlying'); + const id = this.safeString (market, 'symbol'); + const optionParts = id.split ('-'); + const optionBase = this.safeString (optionParts, 0); + const lowercaseId = this.safeStringLower (market, 'symbol'); + const baseId = this.safeString (market, 'baseAsset', optionBase); + const quoteId = this.safeString (market, 'quoteAsset'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const contractType = this.safeString (market, 'contractType'); + let contract = ('contractType' in market); + let expiry = this.safeInteger2 (market, 'deliveryDate', 'expiryDate'); + let settleId = this.safeString (market, 'marginAsset'); + if ((contractType === 'PERPETUAL') || (expiry === 4133404800000)) { // some swap markets do not have contract type, eg: BTCST + expiry = undefined; + swap = true; + } else if (underlying !== undefined) { + contract = true; + option = true; + settleId = (settleId === undefined) ? 'USDT' : settleId; + } else if (expiry !== undefined) { + future = true; + } + const settle = this.safeCurrencyCode (settleId); + const spot = !contract; + const filters = this.safeValue (market, 'filters', []); + const filtersByType = this.indexBy (filters, 'filterType'); + const status = this.safeString2 (market, 'status', 'contractStatus'); + let contractSize = undefined; + let fees = this.fees; + let linear = undefined; + let inverse = undefined; + const strike = this.safeInteger (market, 'strikePrice'); + let symbol = base + '/' + quote; + if (contract) { + if (swap) { + symbol = symbol + ':' + settle; + } else if (future) { + symbol = symbol + ':' + settle + '-' + this.yymmdd (expiry); + } else if (option) { + symbol = symbol + ':' + settle + '-' + this.yymmdd (expiry) + '-' + this.numberToString (strike) + '-' + this.safeString (optionParts, 3); + } + contractSize = this.safeNumber2 (market, 'contractSize', 'unit', this.parseNumber ('1')); + linear = settle === quote; + inverse = settle === base; + const feesType = linear ? 'linear' : 'inverse'; + fees = this.safeValue (this.fees, feesType, {}); + } + let active = (status === 'TRADING'); + if (spot) { + const permissions = this.safeValue (market, 'permissions', []); + for (let j = 0; j < permissions.length; j++) { + if (permissions[j] === 'TRD_GRP_003') { + active = false; + break; + } + } + } + const isMarginTradingAllowed = this.safeValue (market, 'isMarginTradingAllowed', false); + let unifiedType = undefined; + if (spot) { + unifiedType = 'spot'; + } else if (swap) { + unifiedType = 'swap'; + } else if (future) { + unifiedType = 'future'; + } else if (option) { + unifiedType = 'option'; + active = undefined; + } + const entry = { + 'id': id, + 'lowercaseId': lowercaseId, + 'symbol': symbol, + 'base': base, + 'quote': quote, + 'settle': settle, + 'baseId': baseId, + 'quoteId': quoteId, + 'settleId': settleId, + 'type': unifiedType, + 'spot': spot, + 'margin': spot && isMarginTradingAllowed, + 'swap': swap, + 'future': future, + 'option': option, + 'active': active, + 'contract': contract, + 'linear': linear, + 'inverse': inverse, + 'taker': fees['trading']['taker'], + 'maker': fees['trading']['maker'], + 'contractSize': contractSize, + 'expiry': expiry, + 'expiryDatetime': this.iso8601 (expiry), + 'strike': strike, + 'optionType': this.safeStringLower (market, 'side'), + 'precision': { + 'amount': this.safeInteger2 (market, 'quantityPrecision', 'quantityScale'), + 'price': this.safeInteger2 (market, 'pricePrecision', 'priceScale'), + 'base': this.safeInteger (market, 'baseAssetPrecision'), + 'quote': this.safeInteger (market, 'quotePrecision'), + }, + 'limits': { + 'leverage': { + 'min': undefined, + 'max': undefined, + }, + 'amount': { + 'min': this.safeNumber (market, 'minQty'), + 'max': this.safeNumber (market, 'maxQty'), + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': undefined, + 'max': undefined, + }, + }, + 'info': market, + 'created': this.safeInteger (market, 'onboardDate'), // present in inverse & linear apis + }; + if ('PRICE_FILTER' in filtersByType) { + const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {}); + // PRICE_FILTER reports zero values for maxPrice + // since they updated filter types in November 2018 + // https://github.com/ccxt/ccxt/issues/4286 + // therefore limits['price']['max'] doesn't have any meaningful value except undefined + entry['limits']['price'] = { + 'min': this.safeNumber (filter, 'minPrice'), + 'max': this.safeNumber (filter, 'maxPrice'), + }; + entry['precision']['price'] = this.precisionFromString (filter['tickSize']); + } + if ('LOT_SIZE' in filtersByType) { + const filter = this.safeValue (filtersByType, 'LOT_SIZE', {}); + const stepSize = this.safeString (filter, 'stepSize'); + entry['precision']['amount'] = this.precisionFromString (stepSize); + entry['limits']['amount'] = { + 'min': this.safeNumber (filter, 'minQty'), + 'max': this.safeNumber (filter, 'maxQty'), + }; + } + if ('MARKET_LOT_SIZE' in filtersByType) { + const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {}); + entry['limits']['market'] = { + 'min': this.safeNumber (filter, 'minQty'), + 'max': this.safeNumber (filter, 'maxQty'), + }; + } + if (('MIN_NOTIONAL' in filtersByType) || ('NOTIONAL' in filtersByType)) { // notional added in 12/04/23 to spot testnet + const filter = this.safeValue2 (filtersByType, 'MIN_NOTIONAL', 'NOTIONAL', {}); + entry['limits']['cost']['min'] = this.safeNumber2 (filter, 'minNotional', 'notional'); + entry['limits']['cost']['max'] = this.safeNumber (filter, 'maxNotional'); + } + return entry; + } + + parseBalanceHelper (entry) { + const account = this.account (); + account['used'] = this.safeString (entry, 'locked'); + account['free'] = this.safeString (entry, 'free'); + const interest = this.safeString (entry, 'interest'); + const debt = this.safeString (entry, 'borrowed'); + account['debt'] = Precise.stringAdd (debt, interest); + return account; + } + + parseBalance (response, type = undefined, marginMode = undefined): Balances { + const result = { + 'info': response, + }; + let timestamp = undefined; + const isolated = marginMode === 'isolated'; + const cross = (type === 'margin') || (marginMode === 'cross'); + if (!isolated && ((type === 'spot') || cross)) { + timestamp = this.safeInteger (response, 'updateTime'); + const balances = this.safeValue2 (response, 'balances', 'userAssets', []); + for (let i = 0; i < balances.length; i++) { + const balance = balances[i]; + const currencyId = this.safeString (balance, 'asset'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeString (balance, 'free'); + account['used'] = this.safeString (balance, 'locked'); + if (cross) { + const debt = this.safeString (balance, 'borrowed'); + const interest = this.safeString (balance, 'interest'); + account['debt'] = Precise.stringAdd (debt, interest); + } + result[code] = account; + } + } else if (isolated) { + const assets = this.safeValue (response, 'assets'); + for (let i = 0; i < assets.length; i++) { + const asset = assets[i]; + const marketId = this.safeValue (asset, 'symbol'); + const symbol = this.safeSymbol (marketId, undefined, undefined, 'spot'); + const base = this.safeValue (asset, 'baseAsset', {}); + const quote = this.safeValue (asset, 'quoteAsset', {}); + const baseCode = this.safeCurrencyCode (this.safeString (base, 'asset')); + const quoteCode = this.safeCurrencyCode (this.safeString (quote, 'asset')); + const subResult = {}; + subResult[baseCode] = this.parseBalanceHelper (base); + subResult[quoteCode] = this.parseBalanceHelper (quote); + result[symbol] = this.safeBalance (subResult); + } + } else if (type === 'savings') { + const positionAmountVos = this.safeValue (response, 'positionAmountVos', []); + for (let i = 0; i < positionAmountVos.length; i++) { + const entry = positionAmountVos[i]; + const currencyId = this.safeString (entry, 'asset'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + const usedAndTotal = this.safeString (entry, 'amount'); + account['total'] = usedAndTotal; + account['used'] = usedAndTotal; + result[code] = account; + } + } else if (type === 'funding') { + for (let i = 0; i < response.length; i++) { + const entry = response[i]; + const account = this.account (); + const currencyId = this.safeString (entry, 'asset'); + const code = this.safeCurrencyCode (currencyId); + account['free'] = this.safeString (entry, 'free'); + const frozen = this.safeString (entry, 'freeze'); + const withdrawing = this.safeString (entry, 'withdrawing'); + const locked = this.safeString (entry, 'locked'); + account['used'] = Precise.stringAdd (frozen, Precise.stringAdd (locked, withdrawing)); + result[code] = account; + } + } else { + let balances = response; + if (!Array.isArray (response)) { + balances = this.safeValue (response, 'assets', []); + } + for (let i = 0; i < balances.length; i++) { + const balance = balances[i]; + const currencyId = this.safeString (balance, 'asset'); + const code = this.safeCurrencyCode (currencyId); + const account = this.account (); + account['free'] = this.safeString (balance, 'availableBalance'); + account['used'] = this.safeString (balance, 'initialMargin'); + account['total'] = this.safeString2 (balance, 'marginBalance', 'balance'); + result[code] = account; + } + } + result['timestamp'] = timestamp; + result['datetime'] = this.iso8601 (timestamp); + return isolated ? result : this.safeBalance (result); + } + + async fetchBalance (params = {}): Promise { + /** + * @method + * @name binance#fetchBalance + * @description query for balance and get the amount of funds available for trading or funds locked in orders + * @see https://binance-docs.github.io/apidocs/spot/en/#account-information-user_data // spot + * @see https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-account-details-user_data // cross margin + * @see https://binance-docs.github.io/apidocs/spot/en/#query-isolated-margin-account-info-user_data // isolated margin + * @see https://binance-docs.github.io/apidocs/spot/en/#lending-account-user_data // lending + * @see https://binance-docs.github.io/apidocs/spot/en/#funding-wallet-user_data // funding + * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data // future + * @see https://binance-docs.github.io/apidocs/voptions/en/#option-account-information-trade // option + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.type] 'future', 'delivery', 'savings', 'funding', or 'spot' + * @param {string} [params.marginMode] 'cross' or 'isolated', for margin trading, uses this.options.defaultMarginMode if not passed, defaults to undefined/None/null + * @param {string[]|undefined} [params.symbols] unified market symbols, only used in isolated margin mode + * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} + */ + await this.loadMarkets (); + const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot'); + let type = this.safeString (params, 'type', defaultType); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchBalance', undefined, params); + const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchBalance', params); + let method = 'privateGetAccount'; + const request = {}; + if (this.isLinear (type, subType)) { + const options = this.safeValue (this.options, type, {}); + const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {}); + method = this.safeString (fetchBalanceOptions, 'method', 'fapiPrivateV2GetAccount'); + type = 'linear'; + } else if (this.isInverse (type, subType)) { + const options = this.safeValue (this.options, type, {}); + const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {}); + method = this.safeString (fetchBalanceOptions, 'method', 'dapiPrivateGetAccount'); + type = 'inverse'; + } else if (marginMode === 'isolated') { + method = 'sapiGetMarginIsolatedAccount'; + const paramSymbols = this.safeValue (params, 'symbols'); + if (paramSymbols !== undefined) { + let symbols = ''; + if (Array.isArray (paramSymbols)) { + symbols = this.marketId (paramSymbols[0]); + for (let i = 1; i < paramSymbols.length; i++) { + const symbol = paramSymbols[i]; + const id = this.marketId (symbol); + symbols += ',' + id; + } + } else { + symbols = paramSymbols; + } + request['symbols'] = symbols; + } + } else if ((type === 'margin') || (marginMode === 'cross')) { + method = 'sapiGetMarginAccount'; + } else if (type === 'savings') { + method = 'sapiGetLendingUnionAccount'; + } else if (type === 'funding') { + method = 'sapiPostAssetGetFundingAsset'; + } + const requestParams = this.omit (query, [ 'type', 'symbols' ]); + const response = await this[method] (this.extend (request, requestParams)); + // + // spot + // + // { + // "makerCommission": 10, + // "takerCommission": 10, + // "buyerCommission": 0, + // "sellerCommission": 0, + // "canTrade": true, + // "canWithdraw": true, + // "canDeposit": true, + // "updateTime": 1575357359602, + // "accountType": "MARGIN", + // "balances": [ + // { asset: "BTC", free: "0.00219821", locked: "0.00000000" }, + // ] + // } + // + // margin (cross) + // + // { + // "borrowEnabled":true, + // "marginLevel":"999.00000000", + // "totalAssetOfBtc":"0.00000000", + // "totalLiabilityOfBtc":"0.00000000", + // "totalNetAssetOfBtc":"0.00000000", + // "tradeEnabled":true, + // "transferEnabled":true, + // "userAssets":[ + // {"asset":"MATIC","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}, + // {"asset":"VET","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}, + // {"asset":"USDT","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"} + // ], + // } + // + // margin (isolated) + // + // { + // "info": { + // "assets": [ + // { + // "baseAsset": { + // "asset": "1INCH", + // "borrowEnabled": true, + // "borrowed": "0", + // "free": "0", + // "interest": "0", + // "locked": "0", + // "netAsset": "0", + // "netAssetOfBtc": "0", + // "repayEnabled": true, + // "totalAsset": "0" + // }, + // "quoteAsset": { + // "asset": "USDT", + // "borrowEnabled": true, + // "borrowed": "0", + // "free": "11", + // "interest": "0", + // "locked": "0", + // "netAsset": "11", + // "netAssetOfBtc": "0.00054615", + // "repayEnabled": true, + // "totalAsset": "11" + // }, + // "symbol": "1INCHUSDT", + // "isolatedCreated": true, + // "marginLevel": "999", + // "marginLevelStatus": "EXCESSIVE", + // "marginRatio": "5", + // "indexPrice": "0.59184331", + // "liquidatePrice": "0", + // "liquidateRate": "0", + // "tradeEnabled": true, + // "enabled": true + // }, + // ] + // } + // } + // + // futures (fapi) + // + // fapiPrivateV2GetAccount + // + // { + // "feeTier":0, + // "canTrade":true, + // "canDeposit":true, + // "canWithdraw":true, + // "updateTime":0, + // "totalInitialMargin":"0.00000000", + // "totalMaintMargin":"0.00000000", + // "totalWalletBalance":"0.00000000", + // "totalUnrealizedProfit":"0.00000000", + // "totalMarginBalance":"0.00000000", + // "totalPositionInitialMargin":"0.00000000", + // "totalOpenOrderInitialMargin":"0.00000000", + // "totalCrossWalletBalance":"0.00000000", + // "totalCrossUnPnl":"0.00000000", + // "availableBalance":"0.00000000", + // "maxWithdrawAmount":"0.00000000", + // "assets":[ + // { + // "asset":"BNB", + // "walletBalance":"0.01000000", + // "unrealizedProfit":"0.00000000", + // "marginBalance":"0.01000000", + // "maintMargin":"0.00000000", + // "initialMargin":"0.00000000", + // "positionInitialMargin":"0.00000000", + // "openOrderInitialMargin":"0.00000000", + // "maxWithdrawAmount":"0.01000000", + // "crossWalletBalance":"0.01000000", + // "crossUnPnl":"0.00000000", + // "availableBalance":"0.01000000" + // } + // ], + // "positions":[ + // { + // "symbol":"BTCUSDT", + // "initialMargin":"0", + // "maintMargin":"0", + // "unrealizedProfit":"0.00000000", + // "positionInitialMargin":"0", + // "openOrderInitialMargin":"0", + // "leverage":"21", + // "isolated":false, + // "entryPrice":"0.00000", + // "maxNotional":"5000000", + // "positionSide":"BOTH" + // }, + // ] + // } + // + // fapiPrivateV2GetBalance + // + // [ + // { + // "accountAlias":"FzFzXquXXqoC", + // "asset":"BNB", + // "balance":"0.01000000", + // "crossWalletBalance":"0.01000000", + // "crossUnPnl":"0.00000000", + // "availableBalance":"0.01000000", + // "maxWithdrawAmount":"0.01000000" + // } + // ] + // + // savings + // + // { + // "totalAmountInBTC": "0.3172", + // "totalAmountInUSDT": "10000", + // "totalFixedAmountInBTC": "0.3172", + // "totalFixedAmountInUSDT": "10000", + // "totalFlexibleInBTC": "0", + // "totalFlexibleInUSDT": "0", + // "positionAmountVos": [ + // { + // "asset": "USDT", + // "amount": "10000", + // "amountInBTC": "0.3172", + // "amountInUSDT": "10000" + // }, + // { + // "asset": "BUSD", + // "amount": "0", + // "amountInBTC": "0", + // "amountInUSDT": "0" + // } + // ] + // } + // + // binance pay + // + // [ + // { + // "asset": "BUSD", + // "free": "1129.83", + // "locked": "0", + // "freeze": "0", + // "withdrawing": "0" + // } + // ] + // + return this.parseBalance (response, type, marginMode); + } + + async fetchOrderBook (symbol: string, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchOrderBook + * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data + * @see https://binance-docs.github.io/apidocs/spot/en/#order-book // spot + * @see https://binance-docs.github.io/apidocs/futures/en/#order-book // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#order-book // future + * @see https://binance-docs.github.io/apidocs/voptions/en/#order-book // option + * @param {string} symbol unified symbol of the market to fetch the order book for + * @param {int} [limit] the maximum amount of order book entries to return + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols + */ + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + if (limit !== undefined) { + request['limit'] = limit; // default 100, max 5000, see https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book + } + let response = undefined; + if (market['option']) { + response = await this.eapiPublicGetDepth (this.extend (request, params)); + } else if (market['linear']) { + response = await this.fapiPublicGetDepth (this.extend (request, params)); + } else if (market['inverse']) { + response = await this.dapiPublicGetDepth (this.extend (request, params)); + } else { + response = await this.publicGetDepth (this.extend (request, params)); + } + // + // future + // + // { + // "lastUpdateId":333598053905, + // "E":1618631511986, + // "T":1618631511964, + // "bids":[ + // ["2493.56","20.189"], + // ["2493.54","1.000"], + // ["2493.51","0.005"] + // ], + // "asks":[ + // ["2493.57","0.877"], + // ["2493.62","0.063"], + // ["2493.71","12.054"], + // ] + // } + // + // options (eapi) + // + // { + // "bids": [ + // ["108.7","16.08"], + // ["106","21.29"], + // ["82.4","0.02"] + // ], + // "asks": [ + // ["111.4","19.52"], + // ["119.9","17.6"], + // ["141.2","31"] + // ], + // "T": 1676771382078, + // "u": 1015939 + // } + // + const timestamp = this.safeInteger (response, 'T'); + const orderbook = this.parseOrderBook (response, symbol, timestamp); + orderbook['nonce'] = this.safeInteger2 (response, 'lastUpdateId', 'u'); + return orderbook; + } + + parseTicker (ticker, market: Market = undefined): Ticker { + // + // { + // "symbol": "ETHBTC", + // "priceChange": "0.00068700", + // "priceChangePercent": "2.075", + // "weightedAvgPrice": "0.03342681", + // "prevClosePrice": "0.03310300", + // "lastPrice": "0.03378900", + // "lastQty": "0.07700000", + // "bidPrice": "0.03378900", + // "bidQty": "7.16800000", + // "askPrice": "0.03379000", + // "askQty": "24.00000000", + // "openPrice": "0.03310200", + // "highPrice": "0.03388900", + // "lowPrice": "0.03306900", + // "volume": "205478.41000000", + // "quoteVolume": "6868.48826294", + // "openTime": 1601469986932, + // "closeTime": 1601556386932, + // "firstId": 196098772, + // "lastId": 196186315, + // "count": 87544 + // } + // + // coinm + // + // { + // "baseVolume": "214549.95171161", + // "closeTime": "1621965286847", + // "count": "1283779", + // "firstId": "152560106", + // "highPrice": "39938.3", + // "lastId": "153843955", + // "lastPrice": "37993.4", + // "lastQty": "1", + // "lowPrice": "36457.2", + // "openPrice": "37783.4", + // "openTime": "1621878840000", + // "pair": "BTCUSD", + // "priceChange": "210.0", + // "priceChangePercent": "0.556", + // "symbol": "BTCUSD_PERP", + // "volume": "81990451", + // "weightedAvgPrice": "38215.08713747" + // } + // + // eapi: fetchTicker, fetchTickers + // + // { + // "symbol": "ETH-230510-1825-C", + // "priceChange": "-5.1", + // "priceChangePercent": "-0.1854", + // "lastPrice": "22.4", + // "lastQty": "0", + // "open": "27.5", + // "high": "34.1", + // "low": "22.4", + // "volume": "6.83", + // "amount": "201.44", + // "bidPrice": "21.9", + // "askPrice": "22.4", + // "openTime": 1683614771898, + // "closeTime": 1683695017784, + // "firstTradeId": 12, + // "tradeCount": 22, + // "strikePrice": "1825", + // "exercisePrice": "1845.95341176" + // } + // + // spot bidsAsks + // + // { + // "symbol":"ETHBTC", + // "bidPrice":"0.07466800", + // "bidQty":"5.31990000", + // "askPrice":"0.07466900", + // "askQty":"10.93540000" + // } + // + // usdm bidsAsks + // + // { + // "symbol":"BTCUSDT", + // "bidPrice":"21321.90", + // "bidQty":"33.592", + // "askPrice":"21322.00", + // "askQty":"1.427", + // "time":"1673899207538" + // } + // + // coinm bidsAsks + // + // { + // "symbol":"BTCUSD_PERP", + // "pair":"BTCUSD", + // "bidPrice":"21301.2", + // "bidQty":"188", + // "askPrice":"21301.3", + // "askQty":"10302", + // "time":"1673899278514" + // } + // + const timestamp = this.safeInteger (ticker, 'closeTime'); + let marketType = undefined; + if (('time' in ticker)) { + marketType = 'contract'; + } + if (marketType === undefined) { + marketType = ('bidQty' in ticker) ? 'spot' : 'contract'; + } + const marketId = this.safeString (ticker, 'symbol'); + const symbol = this.safeSymbol (marketId, market, undefined, marketType); + const last = this.safeString (ticker, 'lastPrice'); + const isCoinm = ('baseVolume' in ticker); + let baseVolume = undefined; + let quoteVolume = undefined; + if (isCoinm) { + baseVolume = this.safeString (ticker, 'baseVolume'); + quoteVolume = this.safeString (ticker, 'volume'); + } else { + baseVolume = this.safeString (ticker, 'volume'); + quoteVolume = this.safeString2 (ticker, 'quoteVolume', 'amount'); + } + return this.safeTicker ({ + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'high': this.safeString2 (ticker, 'highPrice', 'high'), + 'low': this.safeString2 (ticker, 'lowPrice', 'low'), + 'bid': this.safeString (ticker, 'bidPrice'), + 'bidVolume': this.safeString (ticker, 'bidQty'), + 'ask': this.safeString (ticker, 'askPrice'), + 'askVolume': this.safeString (ticker, 'askQty'), + 'vwap': this.safeString (ticker, 'weightedAvgPrice'), + 'open': this.safeString2 (ticker, 'openPrice', 'open'), + 'close': last, + 'last': last, + 'previousClose': this.safeString (ticker, 'prevClosePrice'), // previous day close + 'change': this.safeString (ticker, 'priceChange'), + 'percentage': this.safeString (ticker, 'priceChangePercent'), + 'average': undefined, + 'baseVolume': baseVolume, + 'quoteVolume': quoteVolume, + 'info': ticker, + }, market); + } + + async fetchStatus (params = {}) { + /** + * @method + * @name binance#fetchStatus + * @description the latest known information on the availability of the exchange API + * @see https://binance-docs.github.io/apidocs/spot/en/#system-status-system + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure} + */ + const response = await this.sapiGetSystemStatus (params); + // + // { + // "status": 0, // 0: normal,1:system maintenance + // "msg": "normal" // "normal", "system_maintenance" + // } + // + const statusRaw = this.safeString (response, 'status'); + return { + 'status': this.safeString ({ '0': 'ok', '1': 'maintenance' }, statusRaw, statusRaw), + 'updated': undefined, + 'eta': undefined, + 'url': undefined, + 'info': response, + }; + } + + async fetchTicker (symbol: string, params = {}): Promise { + /** + * @method + * @name binance#fetchTicker + * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market + * @see https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics // spot + * @see https://binance-docs.github.io/apidocs/spot/en/#rolling-window-price-change-statistics // spot + * @see https://binance-docs.github.io/apidocs/futures/en/#24hr-ticker-price-change-statistics // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#24hr-ticker-price-change-statistics // future + * @see https://binance-docs.github.io/apidocs/voptions/en/#24hr-ticker-price-change-statistics // option + * @param {string} symbol unified symbol of the market to fetch the ticker for + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.rolling] (spot only) default false, if true, uses the rolling 24 hour ticker endpoint /api/v3/ticker + * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + let response = undefined; + if (market['option']) { + response = await this.eapiPublicGetTicker (this.extend (request, params)); + } else if (market['linear']) { + response = await this.fapiPublicGetTicker24hr (this.extend (request, params)); + } else if (market['inverse']) { + response = await this.dapiPublicGetTicker24hr (this.extend (request, params)); + } else { + const rolling = this.safeValue (params, 'rolling', false); + params = this.omit (params, 'rolling'); + if (rolling) { + response = await this.publicGetTicker (this.extend (request, params)); + } else { + response = await this.publicGetTicker24hr (this.extend (request, params)); + } + } + if (Array.isArray (response)) { + const firstTicker = this.safeValue (response, 0, {}); + return this.parseTicker (firstTicker, market); + } + return this.parseTicker (response, market); + } + + async fetchBidsAsks (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchBidsAsks + * @description fetches the bid and ask price and volume for multiple markets + * @see https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker // spot + * @see https://binance-docs.github.io/apidocs/futures/en/#symbol-order-book-ticker // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#symbol-order-book-ticker // future + * @param {string[]|undefined} symbols unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} + */ + await this.loadMarkets (); + symbols = this.marketSymbols (symbols); + let market = undefined; + if (symbols !== undefined) { + const first = this.safeString (symbols, 0); + market = this.market (first); + } + let type = undefined; + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchBidsAsks', market, params); + [ type, params ] = this.handleMarketTypeAndParams ('fetchBidsAsks', market, params); + let response = undefined; + if (this.isLinear (type, subType)) { + response = await this.fapiPublicGetTickerBookTicker (params); + } else if (this.isInverse (type, subType)) { + response = await this.dapiPublicGetTickerBookTicker (params); + } else { + response = await this.publicGetTickerBookTicker (params); + } + return this.parseTickers (response, symbols); + } + + async fetchTickers (symbols: Strings = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchTickers + * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market + * @see https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics // spot + * @see https://binance-docs.github.io/apidocs/futures/en/#24hr-ticker-price-change-statistics // swap + * @see https://binance-docs.github.io/apidocs/delivery/en/#24hr-ticker-price-change-statistics // future + * @see https://binance-docs.github.io/apidocs/voptions/en/#24hr-ticker-price-change-statistics // option + * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} + */ + await this.loadMarkets (); + let type = undefined; + let market = undefined; + symbols = this.marketSymbols (symbols, undefined, true, true, true); + if (symbols !== undefined) { + const first = this.safeString (symbols, 0); + market = this.market (first); + } + [ type, params ] = this.handleMarketTypeAndParams ('fetchTickers', market, params); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchTickers', market, params); + const query = this.omit (params, 'type'); + let defaultMethod = undefined; + if (type === 'option') { + defaultMethod = 'eapiPublicGetTicker'; + } else if (this.isLinear (type, subType)) { + defaultMethod = 'fapiPublicGetTicker24hr'; + } else if (this.isInverse (type, subType)) { + defaultMethod = 'dapiPublicGetTicker24hr'; + } else { + defaultMethod = 'publicGetTicker24hr'; + } + const method = this.safeString (this.options, 'fetchTickersMethod', defaultMethod); + const response = await this[method] (query); + return this.parseTickers (response, symbols); + } + + parseOHLCV (ohlcv, market: Market = undefined): OHLCV { + // when api method = publicGetKlines || fapiPublicGetKlines || dapiPublicGetKlines + // [ + // 1591478520000, // open time + // "0.02501300", // open + // "0.02501800", // high + // "0.02500000", // low + // "0.02500000", // close + // "22.19000000", // volume + // 1591478579999, // close time + // "0.55490906", // quote asset volume, base asset volume for dapi + // 40, // number of trades + // "10.92900000", // taker buy base asset volume + // "0.27336462", // taker buy quote asset volume + // "0" // ignore + // ] + // + // when api method = fapiPublicGetMarkPriceKlines || fapiPublicGetIndexPriceKlines + // [ + // [ + // 1591256460000, // Open time + // "9653.29201333", // Open + // "9654.56401333", // High + // "9653.07367333", // Low + // "9653.07367333", // Close (or latest price) + // "0", // Ignore + // 1591256519999, // Close time + // "0", // Ignore + // 60, // Number of bisic data + // "0", // Ignore + // "0", // Ignore + // "0" // Ignore + // ] + // ] + // + // options + // + // { + // "open": "32.2", + // "high": "32.2", + // "low": "32.2", + // "close": "32.2", + // "volume": "0", + // "interval": "5m", + // "tradeCount": 0, + // "takerVolume": "0", + // "takerAmount": "0", + // "amount": "0", + // "openTime": 1677096900000, + // "closeTime": 1677097200000 + // } + // + const volumeIndex = (market['inverse']) ? 7 : 5; + return [ + this.safeInteger2 (ohlcv, 0, 'closeTime'), + this.safeNumber2 (ohlcv, 1, 'open'), + this.safeNumber2 (ohlcv, 2, 'high'), + this.safeNumber2 (ohlcv, 3, 'low'), + this.safeNumber2 (ohlcv, 4, 'close'), + this.safeNumber2 (ohlcv, volumeIndex, 'volume'), + ]; + } + + async fetchOHLCV (symbol: string, timeframe = '1m', since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchOHLCV + * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market + * @see https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/voptions/en/#kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/futures/en/#index-price-kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/futures/en/#mark-price-kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/delivery/en/#index-price-kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/delivery/en/#mark-price-kline-candlestick-data + * @see https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data + * @param {string} symbol unified symbol of the market to fetch OHLCV data for + * @param {string} timeframe the length of time each candle represents + * @param {int} [since] timestamp in ms of the earliest candle to fetch + * @param {int} [limit] the maximum amount of candles to fetch + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.price] "mark" or "index" for mark price and index price candles + * @param {int} [params.until] timestamp in ms of the latest candle to fetch + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchOHLCV', 'paginate', false); + if (paginate) { + return await this.fetchPaginatedCallDeterministic ('fetchOHLCV', symbol, since, limit, timeframe, params, 1000) as OHLCV[]; + } + const market = this.market (symbol); + // binance docs say that the default limit 500, max 1500 for futures, max 1000 for spot markets + // the reality is that the time range wider than 500 candles won't work right + const defaultLimit = 500; + const maxLimit = 1500; + const price = this.safeString (params, 'price'); + const until = this.safeInteger (params, 'until'); + params = this.omit (params, [ 'price', 'until' ]); + limit = (limit === undefined) ? defaultLimit : Math.min (limit, maxLimit); + const request = { + 'interval': this.safeString (this.timeframes, timeframe, timeframe), + 'limit': limit, + }; + if (price === 'index') { + request['pair'] = market['id']; // Index price takes this argument instead of symbol + } else { + request['symbol'] = market['id']; + } + // const duration = this.parseTimeframe (timeframe); + if (since !== undefined) { + request['startTime'] = since; + // + // It didn't work before without the endTime + // https://github.com/ccxt/ccxt/issues/8454 + // + if (market['inverse']) { + if (since > 0) { + const duration = this.parseTimeframe (timeframe); + const endTime = this.sum (since, limit * duration * 1000 - 1); + const now = this.milliseconds (); + request['endTime'] = Math.min (now, endTime); + } + } + } + if (until !== undefined) { + request['endTime'] = until; + } + let method = 'publicGetKlines'; + if (market['option']) { + method = 'eapiPublicGetKlines'; + } else if (price === 'mark') { + if (market['inverse']) { + method = 'dapiPublicGetMarkPriceKlines'; + } else { + method = 'fapiPublicGetMarkPriceKlines'; + } + } else if (price === 'index') { + if (market['inverse']) { + method = 'dapiPublicGetIndexPriceKlines'; + } else { + method = 'fapiPublicGetIndexPriceKlines'; + } + } else if (market['linear']) { + method = 'fapiPublicGetKlines'; + } else if (market['inverse']) { + method = 'dapiPublicGetKlines'; + } + const response = await this[method] (this.extend (request, params)); + // + // [ + // [1591478520000,"0.02501300","0.02501800","0.02500000","0.02500000","22.19000000",1591478579999,"0.55490906",40,"10.92900000","0.27336462","0"], + // [1591478580000,"0.02499600","0.02500900","0.02499400","0.02500300","21.34700000",1591478639999,"0.53370468",24,"7.53800000","0.18850725","0"], + // [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"], + // ] + // + // options (eapi) + // + // [ + // { + // "open": "32.2", + // "high": "32.2", + // "low": "32.2", + // "close": "32.2", + // "volume": "0", + // "interval": "5m", + // "tradeCount": 0, + // "takerVolume": "0", + // "takerAmount": "0", + // "amount": "0", + // "openTime": 1677096900000, + // "closeTime": 1677097200000 + // } + // ] + // + return this.parseOHLCVs (response, market, timeframe, since, limit); + } + + parseTrade (trade, market: Market = undefined): Trade { + if ('isDustTrade' in trade) { + return this.parseDustTrade (trade, market); + } + // + // aggregate trades + // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list + // + // { + // "a": 26129, // Aggregate tradeId + // "p": "0.01633102", // Price + // "q": "4.70443515", // Quantity + // "f": 27781, // First tradeId + // "l": 27781, // Last tradeId + // "T": 1498793709153, // Timestamp + // "m": true, // Was the buyer the maker? + // "M": true // Was the trade the best price match? + // } + // + // REST: aggregate trades for swap & future (both linear and inverse) + // + // { + // "a": "269772814", + // "p": "25864.1", + // "q": "3", + // "f": "662149354", + // "l": "662149355", + // "T": "1694209776022", + // "m": false, + // } + // + // recent public trades and old public trades + // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#recent-trades-list + // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#old-trade-lookup-market_data + // + // { + // "id": 28457, + // "price": "4.00000100", + // "qty": "12.00000000", + // "time": 1499865549590, + // "isBuyerMaker": true, + // "isBestMatch": true + // } + // + // private trades + // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-trade-list-user_data + // + // { + // "symbol": "BNBBTC", + // "id": 28457, + // "orderId": 100234, + // "price": "4.00000100", + // "qty": "12.00000000", + // "commission": "10.10000000", + // "commissionAsset": "BNB", + // "time": 1499865549590, + // "isBuyer": true, + // "isMaker": false, + // "isBestMatch": true + // } + // + // futures trades + // https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data + // + // { + // "accountId": 20, + // "buyer": False, + // "commission": "-0.07819010", + // "commissionAsset": "USDT", + // "counterPartyId": 653, + // "id": 698759, + // "maker": False, + // "orderId": 25851813, + // "price": "7819.01", + // "qty": "0.002", + // "quoteQty": "0.01563", + // "realizedPnl": "-0.91539999", + // "side": "SELL", + // "symbol": "BTCUSDT", + // "time": 1569514978020 + // } + // { + // "symbol": "BTCUSDT", + // "id": 477128891, + // "orderId": 13809777875, + // "side": "SELL", + // "price": "38479.55", + // "qty": "0.001", + // "realizedPnl": "-0.00009534", + // "marginAsset": "USDT", + // "quoteQty": "38.47955", + // "commission": "-0.00076959", + // "commissionAsset": "USDT", + // "time": 1612733566708, + // "positionSide": "BOTH", + // "maker": true, + // "buyer": false + // } + // + // { respType: FULL } + // + // { + // "price": "4000.00000000", + // "qty": "1.00000000", + // "commission": "4.00000000", + // "commissionAsset": "USDT", + // "tradeId": "1234", + // } + // + // options: fetchMyTrades + // + // { + // "id": 1125899906844226012, + // "tradeId": 73, + // "orderId": 4638761100843040768, + // "symbol": "ETH-230211-1500-C", + // "price": "18.70000000", + // "quantity": "-0.57000000", + // "fee": "0.17305890", + // "realizedProfit": "-3.53400000", + // "side": "SELL", + // "type": "LIMIT", + // "volatility": "0.30000000", + // "liquidity": "MAKER", + // "time": 1676085216845, + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT" + // } + // + // options: fetchTrades + // + // { + // "id": 1, + // "symbol": "ETH-230216-1500-C", + // "price": "35.5", + // "qty": "0.03", + // "quoteQty": "1.065", + // "side": 1, + // "time": 1676366446072 + // } + // + const timestamp = this.safeInteger2 (trade, 'T', 'time'); + const price = this.safeString2 (trade, 'p', 'price'); + let amount = this.safeString2 (trade, 'q', 'qty'); + amount = this.safeString (trade, 'quantity', amount); + const cost = this.safeString2 (trade, 'quoteQty', 'baseQty'); // inverse futures + const marketId = this.safeString (trade, 'symbol'); + const isSpotTrade = ('isIsolated' in trade) || ('M' in trade) || ('orderListId' in trade); + const marketType = isSpotTrade ? 'spot' : 'contract'; + market = this.safeMarket (marketId, market, undefined, marketType); + const symbol = market['symbol']; + let id = this.safeString2 (trade, 't', 'a'); + id = this.safeString2 (trade, 'tradeId', 'id', id); + let side = undefined; + const orderId = this.safeString (trade, 'orderId'); + const buyerMaker = this.safeValue2 (trade, 'm', 'isBuyerMaker'); + let takerOrMaker = undefined; + if (buyerMaker !== undefined) { + side = buyerMaker ? 'sell' : 'buy'; // this is reversed intentionally + } else if ('side' in trade) { + side = this.safeStringLower (trade, 'side'); + } else { + if ('isBuyer' in trade) { + side = trade['isBuyer'] ? 'buy' : 'sell'; // this is a true side + } + } + let fee = undefined; + if ('commission' in trade) { + fee = { + 'cost': this.safeString (trade, 'commission'), + 'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAsset')), + }; + } + if ('isMaker' in trade) { + takerOrMaker = trade['isMaker'] ? 'maker' : 'taker'; + } + if ('maker' in trade) { + takerOrMaker = trade['maker'] ? 'maker' : 'taker'; + } + if (('optionSide' in trade) || market['option']) { + const settle = this.safeCurrencyCode (this.safeString (trade, 'quoteAsset', 'USDT')); + takerOrMaker = this.safeStringLower (trade, 'liquidity'); + if ('fee' in trade) { + fee = { + 'cost': this.safeString (trade, 'fee'), + 'currency': settle, + }; + } + if ((side !== 'buy') && (side !== 'sell')) { + side = (side === '1') ? 'buy' : 'sell'; + } + if ('optionSide' in trade) { + if (side !== 'buy') { + amount = Precise.stringMul ('-1', amount); + } + } + } + return this.safeTrade ({ + 'info': trade, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'id': id, + 'order': orderId, + 'type': this.safeStringLower (trade, 'type'), + 'side': side, + 'takerOrMaker': takerOrMaker, + 'price': price, + 'amount': amount, + 'cost': cost, + 'fee': fee, + }, market); + } + + async fetchTrades (symbol: string, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchTrades + * @description get the list of most recent trades for a particular symbol + * Default fetchTradesMethod + * @see https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list // publicGetAggTrades (spot) + * @see https://binance-docs.github.io/apidocs/futures/en/#compressed-aggregate-trades-list // fapiPublicGetAggTrades (swap) + * @see https://binance-docs.github.io/apidocs/delivery/en/#compressed-aggregate-trades-list // dapiPublicGetAggTrades (future) + * @see https://binance-docs.github.io/apidocs/voptions/en/#recent-trades-list // eapiPublicGetTrades (option) + * Other fetchTradesMethod + * @see https://binance-docs.github.io/apidocs/spot/en/#recent-trades-list // publicGetTrades (spot) + * @see https://binance-docs.github.io/apidocs/futures/en/#recent-trades-list // fapiPublicGetTrades (swap) + * @see https://binance-docs.github.io/apidocs/delivery/en/#recent-trades-list // dapiPublicGetTrades (future) + * @see https://binance-docs.github.io/apidocs/spot/en/#old-trade-lookup-market_data // publicGetHistoricalTrades (spot) + * @see https://binance-docs.github.io/apidocs/future/en/#old-trade-lookup-market_data // fapiPublicGetHistoricalTrades (swap) + * @see https://binance-docs.github.io/apidocs/delivery/en/#old-trade-lookup-market_data // dapiPublicGetHistoricalTrades (future) + * @see https://binance-docs.github.io/apidocs/voptions/en/#old-trade-lookup-market_data // eapiPublicGetHistoricalTrades (option) + * @param {string} symbol unified symbol of the market to fetch trades for + * @param {int} [since] only used when fetchTradesMethod is 'publicGetAggTrades', 'fapiPublicGetAggTrades', or 'dapiPublicGetAggTrades' + * @param {int} [limit] default 500, max 1000 + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {int} [params.until] only used when fetchTradesMethod is 'publicGetAggTrades', 'fapiPublicGetAggTrades', or 'dapiPublicGetAggTrades' + * @param {int} [params.fetchTradesMethod] 'publicGetAggTrades' (spot default), 'fapiPublicGetAggTrades' (swap default), 'dapiPublicGetAggTrades' (future default), 'eapiPublicGetTrades' (option default), 'publicGetTrades', 'fapiPublicGetTrades', 'dapiPublicGetTrades', 'publicGetHistoricalTrades', 'fapiPublicGetHistoricalTrades', 'dapiPublicGetHistoricalTrades', 'eapiPublicGetHistoricalTrades' + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * + * EXCHANGE SPECIFIC PARAMETERS + * @param {int} [params.fromId] trade id to fetch from, default gets most recent trades, not used when fetchTradesMethod is 'publicGetTrades', 'fapiPublicGetTrades', 'dapiPublicGetTrades', or 'eapiPublicGetTrades' + * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchTrades', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchTrades', symbol, since, limit, params) as Trade[]; + } + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + // 'fromId': 123, // ID to get aggregate trades from INCLUSIVE. + // 'startTime': 456, // Timestamp in ms to get aggregate trades from INCLUSIVE. + // 'endTime': 789, // Timestamp in ms to get aggregate trades until INCLUSIVE. + // 'limit': 500, // default = 500, maximum = 1000 + }; + let method = this.safeString (this.options, 'fetchTradesMethod'); + method = this.safeString2 (params, 'fetchTradesMethod', 'method', method); + if (method === undefined) { + if (market['option']) { + method = 'eapiPublicGetTrades'; + } else if (market['linear']) { + method = 'fapiPublicGetAggTrades'; + } else if (market['inverse']) { + method = 'dapiPublicGetAggTrades'; + } else { + method = 'publicGetAggTrades'; + } + } + if (!market['option']) { + if (since !== undefined) { + request['startTime'] = since; + // https://github.com/ccxt/ccxt/issues/6400 + // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list + request['endTime'] = this.sum (since, 3600000); + } + const until = this.safeInteger (params, 'until'); + if (until !== undefined) { + request['endTime'] = until; + } + } + if (limit !== undefined) { + const isFutureOrSwap = (market['swap'] || market['future']); + request['limit'] = isFutureOrSwap ? Math.min (limit, 1000) : limit; // default = 500, maximum = 1000 + } + params = this.omit (params, [ 'until', 'fetchTradesMethod' ]); + // + // Caveats: + // - default limit (500) applies only if no other parameters set, trades up + // to the maximum limit may be returned to satisfy other parameters + // - if both limit and time window is set and time window contains more + // trades than the limit then the last trades from the window are returned + // - "tradeId" accepted and returned by this method is "aggregate" trade id + // which is different from actual trade id + // - setting both fromId and time window results in error + const response = await this[method] (this.extend (request, params)); + // + // aggregate trades + // + // [ + // { + // "a": 26129, // Aggregate tradeId + // "p": "0.01633102", // Price + // "q": "4.70443515", // Quantity + // "f": 27781, // First tradeId + // "l": 27781, // Last tradeId + // "T": 1498793709153, // Timestamp + // "m": true, // Was the buyer the maker? + // "M": true // Was the trade the best price match? + // } + // ] + // + // inverse (swap & future) + // + // [ + // { + // "a": "269772814", + // "p": "25864.1", + // "q": "3", + // "f": "662149354", + // "l": "662149355", + // "T": "1694209776022", + // "m": false, + // }, + // ] + // + // recent public trades and historical public trades + // + // [ + // { + // "id": 28457, + // "price": "4.00000100", + // "qty": "12.00000000", + // "time": 1499865549590, + // "isBuyerMaker": true, + // "isBestMatch": true + // } + // ] + // + // options (eapi) + // + // [ + // { + // "id": 1, + // "symbol": "ETH-230216-1500-C", + // "price": "35.5", + // "qty": "0.03", + // "quoteQty": "1.065", + // "side": 1, + // "time": 1676366446072 + // }, + // ] + // + return this.parseTrades (response, market, since, limit); + } + + async editSpotOrder (id: string, symbol, type, side, amount, price = undefined, params = {}) { + /** + * @method + * @name binance#editSpotOrder + * @ignore + * @description edit a trade order + * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade + * @param {string} id cancel order id + * @param {string} symbol unified symbol of the market to create an order in + * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' + * @param {string} side 'buy' or 'sell' + * @param {float} amount how much of currency you want to trade in units of base currency + * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + if (!market['spot']) { + throw new NotSupported (this.id + ' editSpotOrder() does not support ' + market['type'] + ' orders'); + } + const payload = this.editSpotOrderRequest (id, symbol, type, side, amount, price, params); + const response = await this.privatePostOrderCancelReplace (payload); + // + // spot + // + // { + // "cancelResult": "SUCCESS", + // "newOrderResult": "SUCCESS", + // "cancelResponse": { + // "symbol": "BTCUSDT", + // "origClientOrderId": "web_3f6286480b194b079870ac75fb6978b7", + // "orderId": 16383156620, + // "orderListId": -1, + // "clientOrderId": "Azt6foVTTgHPNhqBf41TTt", + // "price": "14000.00000000", + // "origQty": "0.00110000", + // "executedQty": "0.00000000", + // "cummulativeQuoteQty": "0.00000000", + // "status": "CANCELED", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY" + // }, + // "newOrderResponse": { + // "symbol": "BTCUSDT", + // "orderId": 16383176297, + // "orderListId": -1, + // "clientOrderId": "x-R4BD3S8222ecb58eb9074fb1be018c", + // "transactTime": 1670891847932, + // "price": "13500.00000000", + // "origQty": "0.00085000", + // "executedQty": "0.00000000", + // "cummulativeQuoteQty": "0.00000000", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "fills": [] + // } + // } + // + const data = this.safeValue (response, 'newOrderResponse'); + return this.parseOrder (data, market); + } + + editSpotOrderRequest (id: string, symbol, type, side, amount, price = undefined, params = {}) { + /** + * @method + * @ignore + * @name binance#editSpotOrderRequest + * @description helper function to build request for editSpotOrder + * @param {string} id order id to be edited + * @param {string} symbol unified symbol of the market to create an order in + * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' + * @param {string} side 'buy' or 'sell' + * @param {float} amount how much of currency you want to trade in units of base currency + * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders + * @param {object} params extra parameters specific to the exchange API endpoint + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @returns {object} request to be sent to the exchange + */ + const market = this.market (symbol); + const clientOrderId = this.safeStringN (params, [ 'newClientOrderId', 'clientOrderId', 'origClientOrderId' ]); + const request = { + 'symbol': market['id'], + 'side': side.toUpperCase (), + }; + const initialUppercaseType = type.toUpperCase (); + let uppercaseType = initialUppercaseType; + const postOnly = this.isPostOnly (initialUppercaseType === 'MARKET', initialUppercaseType === 'LIMIT_MAKER', params); + if (postOnly) { + uppercaseType = 'LIMIT_MAKER'; + } + request['type'] = uppercaseType; + const stopPrice = this.safeNumber2 (params, 'stopPrice', 'triggerPrice'); + if (stopPrice !== undefined) { + if (uppercaseType === 'MARKET') { + uppercaseType = 'STOP_LOSS'; + } else if (uppercaseType === 'LIMIT') { + uppercaseType = 'STOP_LOSS_LIMIT'; + } + } + const validOrderTypes = this.safeValue (market['info'], 'orderTypes'); + if (!this.inArray (uppercaseType, validOrderTypes)) { + if (initialUppercaseType !== uppercaseType) { + throw new InvalidOrder (this.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders'); + } else { + throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market'); + } + } + if (clientOrderId === undefined) { + const broker = this.safeValue (this.options, 'broker'); + if (broker !== undefined) { + const brokerId = this.safeString (broker, 'spot'); + if (brokerId !== undefined) { + request['newClientOrderId'] = brokerId + this.uuid22 (); + } + } + } else { + request['newClientOrderId'] = clientOrderId; + } + request['newOrderRespType'] = this.safeValue (this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills + let timeInForceIsRequired = false; + let priceIsRequired = false; + let stopPriceIsRequired = false; + let quantityIsRequired = false; + if (uppercaseType === 'MARKET') { + const quoteOrderQty = this.safeValue (this.options, 'quoteOrderQty', true); + if (quoteOrderQty) { + const quoteOrderQtyNew = this.safeValue2 (params, 'quoteOrderQty', 'cost'); + const precision = market['precision']['price']; + if (quoteOrderQtyNew !== undefined) { + request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQtyNew, TRUNCATE, precision, this.precisionMode); + } else if (price !== undefined) { + const amountString = this.numberToString (amount); + const priceString = this.numberToString (price); + const quoteOrderQuantity = Precise.stringMul (amountString, priceString); + request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQuantity, TRUNCATE, precision, this.precisionMode); + } else { + quantityIsRequired = true; + } + } else { + quantityIsRequired = true; + } + } else if (uppercaseType === 'LIMIT') { + priceIsRequired = true; + timeInForceIsRequired = true; + quantityIsRequired = true; + } else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) { + stopPriceIsRequired = true; + quantityIsRequired = true; + } else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) { + quantityIsRequired = true; + stopPriceIsRequired = true; + priceIsRequired = true; + timeInForceIsRequired = true; + } else if (uppercaseType === 'LIMIT_MAKER') { + priceIsRequired = true; + quantityIsRequired = true; + } + if (quantityIsRequired) { + request['quantity'] = this.amountToPrecision (symbol, amount); + } + if (priceIsRequired) { + if (price === undefined) { + throw new InvalidOrder (this.id + ' editOrder() requires a price argument for a ' + type + ' order'); + } + request['price'] = this.priceToPrecision (symbol, price); + } + if (timeInForceIsRequired) { + request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel + } + if (stopPriceIsRequired) { + if (stopPrice === undefined) { + throw new InvalidOrder (this.id + ' editOrder() requires a stopPrice extra param for a ' + type + ' order'); + } else { + request['stopPrice'] = this.priceToPrecision (symbol, stopPrice); + } + } + request['cancelReplaceMode'] = 'STOP_ON_FAILURE'; // If the cancel request fails, the new order placement will not be attempted. + const cancelId = this.safeString2 (params, 'cancelNewClientOrderId', 'cancelOrigClientOrderId'); + if (cancelId === undefined) { + request['cancelOrderId'] = id; // user can provide either cancelOrderId, cancelOrigClientOrderId or cancelOrigClientOrderId + } + // remove timeInForce from params because PO is only used by this.isPostOnly and it's not a valid value for Binance + if (this.safeString (params, 'timeInForce') === 'PO') { + params = this.omit (params, [ 'timeInForce' ]); + } + params = this.omit (params, [ 'quoteOrderQty', 'cost', 'stopPrice', 'newClientOrderId', 'clientOrderId', 'postOnly' ]); + return this.extend (request, params); + } + + async editContractOrder (id: string, symbol, type, side, amount, price = undefined, params = {}) { + /** + * @method + * @name binance#editContractOrder + * @description edit a trade order + * @see https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-order-trade + * @param {string} id cancel order id + * @param {string} symbol unified symbol of the market to create an order in + * @param {string} type 'market' or 'limit' + * @param {string} side 'buy' or 'sell' + * @param {float} amount how much of currency you want to trade in units of base currency + * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + if (!market['contract']) { + throw new NotSupported (this.id + ' editContractOrder() does not support ' + market['type'] + ' orders'); + } + const request = { + 'symbol': market['id'], + 'side': side.toUpperCase (), + }; + const clientOrderId = this.safeStringN (params, [ 'newClientOrderId', 'clientOrderId', 'origClientOrderId' ]); + request['orderId'] = id; + request['quantity'] = this.amountToPrecision (symbol, amount); + if (price !== undefined) { + request['price'] = this.priceToPrecision (symbol, price); + } + if (clientOrderId !== undefined) { + request['origClientOrderId'] = clientOrderId; + } + params = this.omit (params, [ 'clientOrderId', 'newClientOrderId' ]); + let response = undefined; + if (market['linear']) { + response = await this.fapiPrivatePutOrder (this.extend (request, params)); + } else if (market['inverse']) { + response = await this.dapiPrivatePutOrder (this.extend (request, params)); + } + // + // swap and future + // + // { + // "orderId": 151007482392, + // "symbol": "BTCUSDT", + // "status": "NEW", + // "clientOrderId": "web_pCCGp9AIHjziKLlpGpXI", + // "price": "25000", + // "avgPrice": "0.00000", + // "origQty": "0.001", + // "executedQty": "0", + // "cumQty": "0", + // "cumQuote": "0", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "BUY", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, + // "origType": "LIMIT", + // "updateTime": 1684300587845 + // } + // + return this.parseOrder (response, market); + } + + async editOrder (id: string, symbol, type, side, amount = undefined, price = undefined, params = {}) { + /** + * @method + * @name binance#editOrder + * @description edit a trade order + * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-order-trade + * @param {string} id cancel order id + * @param {string} symbol unified symbol of the market to create an order in + * @param {string} type 'market' or 'limit' + * @param {string} side 'buy' or 'sell' + * @param {float} amount how much of currency you want to trade in units of base currency + * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + if (market['option']) { + throw new NotSupported (this.id + ' editOrder() does not support ' + market['type'] + ' orders'); + } + if (market['spot']) { + return await this.editSpotOrder (id, symbol, type, side, amount, price, params); + } else { + return await this.editContractOrder (id, symbol, type, side, amount, price, params); + } + } + + parseOrderStatus (status) { + const statuses = { + 'NEW': 'open', + 'PARTIALLY_FILLED': 'open', + 'ACCEPTED': 'open', + 'FILLED': 'closed', + 'CANCELED': 'canceled', + 'CANCELLED': 'canceled', + 'PENDING_CANCEL': 'canceling', // currently unused + 'REJECTED': 'rejected', + 'EXPIRED': 'expired', + 'EXPIRED_IN_MATCH': 'expired', + }; + return this.safeString (statuses, status, status); + } + + parseOrder (order, market: Market = undefined): Order { + // + // spot + // + // { + // "symbol": "LTCBTC", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "0.0", + // "cummulativeQuoteQty": "0.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "icebergQty": "0.0", + // "time": 1499827319559, + // "updateTime": 1499827319559, + // "isWorking": true + // } + // + // spot: editOrder + // + // { + // "symbol": "BTCUSDT", + // "orderId": 16383176297, + // "orderListId": -1, + // "clientOrderId": "x-R4BD3S8222ecb58eb9074fb1be018c", + // "transactTime": 1670891847932, + // "price": "13500.00000000", + // "origQty": "0.00085000", + // "executedQty": "0.00000000", + // "cummulativeQuoteQty": "0.00000000", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "fills": [] + // } + // + // swap and future: editOrder + // + // { + // "orderId": 151007482392, + // "symbol": "BTCUSDT", + // "status": "NEW", + // "clientOrderId": "web_pCCGp9AIHjziKLlpGpXI", + // "price": "25000", + // "avgPrice": "0.00000", + // "origQty": "0.001", + // "executedQty": "0", + // "cumQty": "0", + // "cumQuote": "0", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "BUY", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, + // "origType": "LIMIT", + // "updateTime": 1684300587845 + // } + // + // futures + // + // { + // "symbol": "BTCUSDT", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "1.0", + // "cumQuote": "10.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "updateTime": 1499827319559 + // } + // + // createOrder with { "newOrderRespType": "FULL" } + // + // { + // "symbol": "BTCUSDT", + // "orderId": 5403233939, + // "orderListId": -1, + // "clientOrderId": "x-R4BD3S825e669e75b6c14f69a2c43e", + // "transactTime": 1617151923742, + // "price": "0.00000000", + // "origQty": "0.00050000", + // "executedQty": "0.00050000", + // "cummulativeQuoteQty": "29.47081500", + // "status": "FILLED", + // "timeInForce": "GTC", + // "type": "MARKET", + // "side": "BUY", + // "fills": [ + // { + // "price": "58941.63000000", + // "qty": "0.00050000", + // "commission": "0.00007050", + // "commissionAsset": "BNB", + // "tradeId": 737466631 + // } + // ] + // } + // + // delivery + // + // { + // "orderId": "18742727411", + // "symbol": "ETHUSD_PERP", + // "pair": "ETHUSD", + // "status": "FILLED", + // "clientOrderId": "x-xcKtGhcu3e2d1503fdd543b3b02419", + // "price": "0", + // "avgPrice": "4522.14", + // "origQty": "1", + // "executedQty": "1", + // "cumBase": "0.00221134", + // "timeInForce": "GTC", + // "type": "MARKET", + // "reduceOnly": false, + // "closePosition": false, + // "side": "SELL", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, + // "origType": "MARKET", + // "time": "1636061952660", + // "updateTime": "1636061952660" + // } + // + // option: createOrder, fetchOrder, fetchOpenOrders, fetchOrders + // + // { + // "orderId": 4728833085436977152, + // "symbol": "ETH-230211-1500-C", + // "price": "10.0", + // "quantity": "1.00", + // "executedQty": "0.00", + // "fee": "0", + // "side": "BUY", + // "type": "LIMIT", + // "timeInForce": "GTC", + // "reduceOnly": false, + // "postOnly": false, + // "createTime": 1676083034462, + // "updateTime": 1676083034462, + // "status": "ACCEPTED", + // "avgPrice": "0", + // "source": "API", + // "clientOrderId": "", + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT", + // "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"}, + // "mmp": false + // } + // { + // cancelOrders/createOrders + // "code": -4005, + // "msg": "Quantity greater than max quantity." + // }, + // + const code = this.safeString (order, 'code'); + if (code !== undefined) { + // cancelOrders/createOrders might have a partial success + return this.safeOrder ({ 'info': order, 'status': 'rejected' }, market); + } + const status = this.parseOrderStatus (this.safeString (order, 'status')); + const marketId = this.safeString (order, 'symbol'); + const marketType = ('closePosition' in order) ? 'contract' : 'spot'; + const symbol = this.safeSymbol (marketId, market, undefined, marketType); + const filled = this.safeString (order, 'executedQty', '0'); + const timestamp = this.safeIntegerN (order, [ 'time', 'createTime', 'workingTime', 'transactTime', 'updateTime' ]); // order of the keys matters here + let lastTradeTimestamp = undefined; + if (('transactTime' in order) || ('updateTime' in order)) { + const timestampValue = this.safeInteger2 (order, 'updateTime', 'transactTime'); + if (status === 'open') { + if (Precise.stringGt (filled, '0')) { + lastTradeTimestamp = timestampValue; + } + } else if (status === 'closed') { + lastTradeTimestamp = timestampValue; + } + } + const lastUpdateTimestamp = this.safeInteger2 (order, 'transactTime', 'updateTime'); + const average = this.safeString (order, 'avgPrice'); + const price = this.safeString (order, 'price'); + const amount = this.safeString2 (order, 'origQty', 'quantity'); + // - Spot/Margin market: cummulativeQuoteQty + // - Futures market: cumQuote. + // Note this is not the actual cost, since Binance futures uses leverage to calculate margins. + let cost = this.safeString2 (order, 'cummulativeQuoteQty', 'cumQuote'); + cost = this.safeString (order, 'cumBase', cost); + const id = this.safeString (order, 'orderId'); + let type = this.safeStringLower (order, 'type'); + const side = this.safeStringLower (order, 'side'); + const fills = this.safeValue (order, 'fills', []); + const clientOrderId = this.safeString (order, 'clientOrderId'); + let timeInForce = this.safeString (order, 'timeInForce'); + if (timeInForce === 'GTX') { + // GTX means "Good Till Crossing" and is an equivalent way of saying Post Only + timeInForce = 'PO'; + } + const postOnly = (type === 'limit_maker') || (timeInForce === 'PO'); + if (type === 'limit_maker') { + type = 'limit'; + } + const stopPriceString = this.safeString (order, 'stopPrice'); + const stopPrice = this.parseNumber (this.omitZero (stopPriceString)); + return this.safeOrder ({ + 'info': order, + 'id': id, + 'clientOrderId': clientOrderId, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'lastTradeTimestamp': lastTradeTimestamp, + 'lastUpdateTimestamp': lastUpdateTimestamp, + 'symbol': symbol, + 'type': type, + 'timeInForce': timeInForce, + 'postOnly': postOnly, + 'reduceOnly': this.safeValue (order, 'reduceOnly'), + 'side': side, + 'price': price, + 'triggerPrice': stopPrice, + 'amount': amount, + 'cost': cost, + 'average': average, + 'filled': filled, + 'remaining': undefined, + 'status': status, + 'fee': { + 'currency': this.safeString (order, 'quoteAsset'), + 'cost': this.safeNumber (order, 'fee'), + 'rate': undefined, + }, + 'trades': fills, + }, market); + } + + async createOrders (orders: OrderRequest[], params = {}) { + /** + * @method + * @name binance#createOrders + * @description *contract only* create a list of trade orders + * @see https://binance-docs.github.io/apidocs/futures/en/#place-multiple-orders-trade + * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params + * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + await this.loadMarkets (); + const ordersRequests = []; + let orderSymbols = []; + for (let i = 0; i < orders.length; i++) { + const rawOrder = orders[i]; + const marketId = this.safeString (rawOrder, 'symbol'); + orderSymbols.push (marketId); + const type = this.safeString (rawOrder, 'type'); + const side = this.safeString (rawOrder, 'side'); + const amount = this.safeValue (rawOrder, 'amount'); + const price = this.safeValue (rawOrder, 'price'); + const orderParams = this.safeValue (rawOrder, 'params', {}); + const orderRequest = this.createOrderRequest (marketId, type, side, amount, price, orderParams); + ordersRequests.push (orderRequest); + } + orderSymbols = this.marketSymbols (orderSymbols, undefined, false, true, true); + const market = this.market (orderSymbols[0]); + if (market['spot']) { + throw new NotSupported (this.id + ' createOrders() does not support ' + market['type'] + ' orders'); + } + let response = undefined; + let request = { + 'batchOrders': ordersRequests, + }; + request = this.extend (request, params); + if (market['linear']) { + response = await this.fapiPrivatePostBatchOrders (request); + } else if (market['option']) { + response = await this.eapiPrivatePostBatchOrders (request); + } else { + response = await this.dapiPrivatePostBatchOrders (request); + } + // + // [ + // { + // "code": -4005, + // "msg": "Quantity greater than max quantity." + // }, + // { + // "orderId": 650640530, + // "symbol": "LTCUSDT", + // "status": "NEW", + // "clientOrderId": "x-xcKtGhcu32184eb13585491289bbaf", + // "price": "54.00", + // "avgPrice": "0.00", + // "origQty": "0.100", + // "executedQty": "0.000", + // "cumQty": "0.000", + // "cumQuote": "0.00000", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "BUY", + // "positionSide": "BOTH", + // "stopPrice": "0.00", + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, + // "origType": "LIMIT", + // "priceMatch": "NONE", + // "selfTradePreventionMode": "NONE", + // "goodTillDate": 0, + // "updateTime": 1698073926929 + // } + // ] + // + return this.parseOrders (response); + } + + async createOrder (symbol: string, type: OrderType, side: OrderSide, amount, price = undefined, params = {}) { + /** + * @method + * @name binance#createOrder + * @description create a trade order + * @see https://binance-docs.github.io/apidocs/spot/en/#new-order-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#test-new-order-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#new-order-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#new-order-trade + * @see https://binance-docs.github.io/apidocs/voptions/en/#new-order-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#new-order-using-sor-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#test-new-order-using-sor-trade + * @param {string} symbol unified symbol of the market to create an order in + * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' + * @param {string} side 'buy' or 'sell' + * @param {float} amount how much of currency you want to trade in units of base currency + * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false + * @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false + * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const marketType = this.safeString (params, 'type', market['type']); + const [ marginMode, query ] = this.handleMarginModeAndParams ('createOrder', params); + const sor = this.safeValue2 (params, 'sor', 'SOR', false); + params = this.omit (params, 'sor', 'SOR'); + const request = this.createOrderRequest (symbol, type, side, amount, price, params); + let method = 'privatePostOrder'; + if (sor) { + method = 'privatePostSorOrder'; + } else if (market['linear']) { + method = 'fapiPrivatePostOrder'; + } else if (market['inverse']) { + method = 'dapiPrivatePostOrder'; + } else if (marketType === 'margin' || marginMode !== undefined) { + method = 'sapiPostMarginOrder'; + } + if (market['option']) { + method = 'eapiPrivatePostOrder'; + } + // support for testing orders + if (market['spot'] || marketType === 'margin') { + const test = this.safeValue (query, 'test', false); + if (test) { + method += 'Test'; + } + } + const response = await this[method] (request); + return this.parseOrder (response, market); + } + + createOrderRequest (symbol: string, type: OrderType, side: OrderSide, amount, price = undefined, params = {}) { + /** + * @method + * @ignore + * @name binance#createOrderRequest + * @description helper function to build request + * @param {string} symbol unified symbol of the market to create an order in + * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' + * @param {string} side 'buy' or 'sell' + * @param {float} amount how much of currency you want to trade in units of base currency + * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders + * @param {object} params extra parameters specific to the exchange API endpoint + * @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading + * @returns {object} request to be sent to the exchange + */ + const market = this.market (symbol); + const marketType = this.safeString (params, 'type', market['type']); + const clientOrderId = this.safeString2 (params, 'newClientOrderId', 'clientOrderId'); + const initialUppercaseType = type.toUpperCase (); + const isMarketOrder = initialUppercaseType === 'MARKET'; + const isLimitOrder = initialUppercaseType === 'LIMIT'; + const postOnly = this.isPostOnly (isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params); + const triggerPrice = this.safeValue2 (params, 'triggerPrice', 'stopPrice'); + const stopLossPrice = this.safeValue (params, 'stopLossPrice', triggerPrice); // fallback to stopLoss + const takeProfitPrice = this.safeValue (params, 'takeProfitPrice'); + const trailingDelta = this.safeValue (params, 'trailingDelta'); + const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined; + const isTakeProfit = takeProfitPrice !== undefined; + params = this.omit (params, [ 'type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice' ]); + const [ marginMode, query ] = this.handleMarginModeAndParams ('createOrder', params); + const request = { + 'symbol': market['id'], + 'side': side.toUpperCase (), + }; + if (market['spot'] || marketType === 'margin') { + // only supported for spot/margin api (all margin markets are spot markets) + if (postOnly) { + type = 'LIMIT_MAKER'; + } + } + if (marketType === 'margin' || marginMode !== undefined) { + const reduceOnly = this.safeValue (params, 'reduceOnly'); + if (reduceOnly) { + request['sideEffectType'] = 'AUTO_REPAY'; + params = this.omit (params, 'reduceOnly'); + } + } + let uppercaseType = type.toUpperCase (); + let stopPrice = undefined; + if (isStopLoss) { + stopPrice = stopLossPrice; + if (isMarketOrder) { + // spot STOP_LOSS market orders are not a valid order type + uppercaseType = market['contract'] ? 'STOP_MARKET' : 'STOP_LOSS'; + } else if (isLimitOrder) { + uppercaseType = market['contract'] ? 'STOP' : 'STOP_LOSS_LIMIT'; + } + } else if (isTakeProfit) { + stopPrice = takeProfitPrice; + if (isMarketOrder) { + // spot TAKE_PROFIT market orders are not a valid order type + uppercaseType = market['contract'] ? 'TAKE_PROFIT_MARKET' : 'TAKE_PROFIT'; + } else if (isLimitOrder) { + uppercaseType = market['contract'] ? 'TAKE_PROFIT' : 'TAKE_PROFIT_LIMIT'; + } + } + if (marginMode === 'isolated') { + request['isIsolated'] = true; + } + if (clientOrderId === undefined) { + const broker = this.safeValue (this.options, 'broker', {}); + const defaultId = (market['contract']) ? 'x-xcKtGhcu' : 'x-R4BD3S82'; + const brokerId = this.safeString (broker, marketType, defaultId); + request['newClientOrderId'] = brokerId + this.uuid22 (); + } else { + request['newClientOrderId'] = clientOrderId; + } + if ((marketType === 'spot') || (marketType === 'margin')) { + request['newOrderRespType'] = this.safeValue (this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills + } else { + // swap, futures and options + request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK" + } + if (market['option']) { + if (type === 'market') { + throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market'); + } + } else { + const validOrderTypes = this.safeValue (market['info'], 'orderTypes'); + if (!this.inArray (uppercaseType, validOrderTypes)) { + if (initialUppercaseType !== uppercaseType) { + throw new InvalidOrder (this.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders'); + } else { + throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market'); + } + } + } + request['type'] = uppercaseType; + // additional required fields depending on the order type + let timeInForceIsRequired = false; + let priceIsRequired = false; + let stopPriceIsRequired = false; + let quantityIsRequired = false; + // + // spot/margin + // + // LIMIT timeInForce, quantity, price + // MARKET quantity or quoteOrderQty + // STOP_LOSS quantity, stopPrice + // STOP_LOSS_LIMIT timeInForce, quantity, price, stopPrice + // TAKE_PROFIT quantity, stopPrice + // TAKE_PROFIT_LIMIT timeInForce, quantity, price, stopPrice + // LIMIT_MAKER quantity, price + // + // futures + // + // LIMIT timeInForce, quantity, price + // MARKET quantity + // STOP/TAKE_PROFIT quantity, price, stopPrice + // STOP_MARKET stopPrice + // TAKE_PROFIT_MARKET stopPrice + // TRAILING_STOP_MARKET callbackRate + // + if (uppercaseType === 'MARKET') { + if (market['spot']) { + const quoteOrderQty = this.safeValue (this.options, 'quoteOrderQty', true); + if (quoteOrderQty) { + const quoteOrderQtyNew = this.safeValue2 (query, 'quoteOrderQty', 'cost'); + const precision = market['precision']['price']; + if (quoteOrderQtyNew !== undefined) { + request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQtyNew, TRUNCATE, precision, this.precisionMode); + } else if (price !== undefined) { + const amountString = this.numberToString (amount); + const priceString = this.numberToString (price); + const quoteOrderQuantity = Precise.stringMul (amountString, priceString); + request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQuantity, TRUNCATE, precision, this.precisionMode); + } else { + quantityIsRequired = true; + } + } else { + quantityIsRequired = true; + } + } else { + quantityIsRequired = true; + } + } else if (uppercaseType === 'LIMIT') { + priceIsRequired = true; + timeInForceIsRequired = true; + quantityIsRequired = true; + } else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) { + stopPriceIsRequired = true; + quantityIsRequired = true; + if (market['linear'] || market['inverse']) { + priceIsRequired = true; + } + } else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) { + quantityIsRequired = true; + stopPriceIsRequired = true; + priceIsRequired = true; + timeInForceIsRequired = true; + } else if (uppercaseType === 'LIMIT_MAKER') { + priceIsRequired = true; + quantityIsRequired = true; + } else if (uppercaseType === 'STOP') { + quantityIsRequired = true; + stopPriceIsRequired = true; + priceIsRequired = true; + } else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) { + const closePosition = this.safeValue (query, 'closePosition'); + if (closePosition === undefined) { + quantityIsRequired = true; + } + stopPriceIsRequired = true; + } else if (uppercaseType === 'TRAILING_STOP_MARKET') { + quantityIsRequired = true; + const callbackRate = this.safeNumber (query, 'callbackRate'); + if (callbackRate === undefined) { + throw new InvalidOrder (this.id + ' createOrder() requires a callbackRate extra param for a ' + type + ' order'); + } + } + if (quantityIsRequired) { + request['quantity'] = this.amountToPrecision (symbol, amount); + } + if (priceIsRequired) { + if (price === undefined) { + throw new InvalidOrder (this.id + ' createOrder() requires a price argument for a ' + type + ' order'); + } + request['price'] = this.priceToPrecision (symbol, price); + } + if (timeInForceIsRequired) { + request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel + } + if (market['contract'] && postOnly) { + request['timeInForce'] = 'GTX'; + } + if (stopPriceIsRequired) { + if (market['contract']) { + if (stopPrice === undefined) { + throw new InvalidOrder (this.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order'); + } + } else { + // check for delta price as well + if (trailingDelta === undefined && stopPrice === undefined) { + throw new InvalidOrder (this.id + ' createOrder() requires a stopPrice or trailingDelta param for a ' + type + ' order'); + } + } + if (stopPrice !== undefined) { + request['stopPrice'] = this.priceToPrecision (symbol, stopPrice); + } + } + // remove timeInForce from params because PO is only used by this.isPostOnly and it's not a valid value for Binance + if (this.safeString (params, 'timeInForce') === 'PO') { + params = this.omit (params, [ 'timeInForce' ]); + } + const requestParams = this.omit (params, [ 'quoteOrderQty', 'cost', 'stopPrice', 'test', 'type', 'newClientOrderId', 'clientOrderId', 'postOnly' ]); + return this.extend (request, requestParams); + } + + async fetchOrder (id: string, symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#fetchOrder + * @description fetches information on an order made by the user + * @see https://binance-docs.github.io/apidocs/spot/en/#query-order-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#query-order-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#query-order-user_data + * @see https://binance-docs.github.io/apidocs/voptions/en/#query-single-order-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-order-user_data + * @param {string} symbol unified symbol of the market the order was made in + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchOrder', params); + const request = { + 'symbol': market['id'], + }; + let method = 'privateGetOrder'; + if (market['option']) { + method = 'eapiPrivateGetOrder'; + } else if (market['linear']) { + method = 'fapiPrivateGetOrder'; + } else if (market['inverse']) { + method = 'dapiPrivateGetOrder'; + } else if (type === 'margin' || marginMode !== undefined) { + method = 'sapiGetMarginOrder'; + if (marginMode === 'isolated') { + request['isIsolated'] = true; + } + } + const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); + if (clientOrderId !== undefined) { + if (market['option']) { + request['clientOrderId'] = clientOrderId; + } else { + request['origClientOrderId'] = clientOrderId; + } + } else { + request['orderId'] = id; + } + const requestParams = this.omit (query, [ 'type', 'clientOrderId', 'origClientOrderId' ]); + const response = await this[method] (this.extend (request, requestParams)); + return this.parseOrder (response, market); + } + + async fetchOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchOrders + * @description fetches information on multiple orders made by the user + * @see https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-orders-user_data + * @param {string} symbol unified market symbol of the market orders were made in + * @param {int} [since] the earliest time in ms to fetch orders for + * @param {int} [limit] the maximum number of order structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @param {int} [params.until] the latest time in ms to fetch orders for + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument'); + } + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchOrders', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchOrders', symbol, since, limit, params) as Order[]; + } + const market = this.market (symbol); + const defaultType = this.safeString2 (this.options, 'fetchOrders', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchOrders', params); + const request = { + 'symbol': market['id'], + }; + let method = 'privateGetAllOrders'; + if (market['option']) { + method = 'eapiPrivateGetHistoryOrders'; + } else if (market['linear']) { + method = 'fapiPrivateGetAllOrders'; + } else if (market['inverse']) { + method = 'dapiPrivateGetAllOrders'; + } else if (type === 'margin' || marginMode !== undefined) { + method = 'sapiGetMarginAllOrders'; + if (marginMode === 'isolated') { + request['isIsolated'] = true; + } + } + const until = this.safeInteger (params, 'until'); + if (until !== undefined) { + params = this.omit (params, 'until'); + request['endTime'] = until; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this[method] (this.extend (request, query)); + // + // spot + // + // [ + // { + // "symbol": "LTCBTC", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "0.0", + // "cummulativeQuoteQty": "0.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "icebergQty": "0.0", + // "time": 1499827319559, + // "updateTime": 1499827319559, + // "isWorking": true + // } + // ] + // + // futures + // + // [ + // { + // "symbol": "BTCUSDT", + // "orderId": 1, + // "clientOrderId": "myOrder1", + // "price": "0.1", + // "origQty": "1.0", + // "executedQty": "1.0", + // "cumQuote": "10.0", + // "status": "NEW", + // "timeInForce": "GTC", + // "type": "LIMIT", + // "side": "BUY", + // "stopPrice": "0.0", + // "updateTime": 1499827319559 + // } + // ] + // + // options + // + // [ + // { + // "orderId": 4728833085436977152, + // "symbol": "ETH-230211-1500-C", + // "price": "10.0", + // "quantity": "1.00", + // "executedQty": "0.00", + // "fee": "0", + // "side": "BUY", + // "type": "LIMIT", + // "timeInForce": "GTC", + // "reduceOnly": false, + // "postOnly": false, + // "createTime": 1676083034462, + // "updateTime": 1676083034462, + // "status": "ACCEPTED", + // "avgPrice": "0", + // "source": "API", + // "clientOrderId": "", + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT", + // "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"}, + // "mmp": false + // } + // ] + // + return this.parseOrders (response, market, since, limit); + } + + async fetchOpenOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchOpenOrders + * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data + * @see https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data + * @description fetch all unfilled currently open orders + * @see https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data + * @see https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-orders-user_data + * @param {string} symbol unified market symbol + * @param {int} [since] the earliest time in ms to fetch open orders for + * @param {int} [limit] the maximum number of open orders structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + await this.loadMarkets (); + let market = undefined; + let type = undefined; + const request = {}; + let marginMode = undefined; + let query = undefined; + [ marginMode, query ] = this.handleMarginModeAndParams ('fetchOpenOrders', params); + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot'); + const marketType = ('type' in market) ? market['type'] : defaultType; + type = this.safeString (query, 'type', marketType); + } else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) { + const symbols = this.symbols; + const numSymbols = symbols.length; + const fetchOpenOrdersRateLimit = this.parseToInt (numSymbols / 2); + throw new ExchangeError (this.id + ' fetchOpenOrders() WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + fetchOpenOrdersRateLimit.toString () + ' seconds. Do not call this method frequently to avoid ban. Set ' + this.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = false to suppress this warning message.'); + } else { + const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot'); + type = this.safeString (query, 'type', defaultType); + } + let subType = undefined; + [ subType, query ] = this.handleSubTypeAndParams ('fetchOpenOrders', market, query); + const requestParams = this.omit (query, 'type'); + let method = 'privateGetOpenOrders'; + if (type === 'option') { + method = 'eapiPrivateGetOpenOrders'; + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + } else if (this.isLinear (type, subType)) { + method = 'fapiPrivateGetOpenOrders'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateGetOpenOrders'; + } else if (type === 'margin' || marginMode !== undefined) { + method = 'sapiGetMarginOpenOrders'; + if (marginMode === 'isolated') { + request['isIsolated'] = true; + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument for isolated markets'); + } + } + } + const response = await this[method] (this.extend (request, requestParams)); + return this.parseOrders (response, market, since, limit); + } + + async fetchClosedOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchClosedOrders + * @description fetches information on multiple closed orders made by the user + * @see https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-orders-user_data + * @param {string} symbol unified market symbol of the market orders were made in + * @param {int} [since] the earliest time in ms to fetch orders for + * @param {int} [limit] the maximum number of order structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + const orders = await this.fetchOrders (symbol, since, limit, params); + return this.filterBy (orders, 'status', 'closed') as Order[]; + } + + async fetchCanceledOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchCanceledOrders + * @description fetches information on multiple canceled orders made by the user + * @see https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-orders-user_data + * @see https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade + * @param {string} symbol unified market symbol of the market the orders were made in + * @param {int} [since] the earliest time in ms to fetch orders for + * @param {int} [limit] the maximum number of order structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchCanceledOrders() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + if (market['swap'] || market['future']) { + throw new NotSupported (this.id + ' fetchCanceledOrders() supports spot, margin and option markets only'); + } + params = this.omit (params, 'type'); + const orders = await this.fetchOrders (symbol, since, undefined, params); + const filteredOrders = this.filterBy (orders, 'status', 'canceled'); + return this.filterByLimit (filteredOrders, limit); + } + + async cancelOrder (id: string, symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#cancelOrder + * @description cancels an open order + * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-order-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-order-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-order-trade + * @see https://binance-docs.github.io/apidocs/voptions/en/#cancel-option-order-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade + * @param {string} id order id + * @param {string} symbol unified symbol of the market the order was made in + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const defaultType = this.safeString2 (this.options, 'cancelOrder', 'defaultType', 'spot'); + const type = this.safeString (params, 'type', defaultType); + const [ marginMode, query ] = this.handleMarginModeAndParams ('cancelOrder', params); + const request = { + 'symbol': market['id'], + // 'orderId': id, + // 'origClientOrderId': id, + }; + const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); + if (clientOrderId !== undefined) { + if (market['option']) { + request['clientOrderId'] = clientOrderId; + } else { + request['origClientOrderId'] = clientOrderId; + } + } else { + request['orderId'] = id; + } + let method = 'privateDeleteOrder'; + if (market['option']) { + method = 'eapiPrivateDeleteOrder'; + } else if (market['linear']) { + method = 'fapiPrivateDeleteOrder'; + } else if (market['inverse']) { + method = 'dapiPrivateDeleteOrder'; + } else if (type === 'margin' || marginMode !== undefined) { + method = 'sapiDeleteMarginOrder'; + if (marginMode === 'isolated') { + request['isIsolated'] = true; + } + } + const requestParams = this.omit (query, [ 'type', 'origClientOrderId', 'clientOrderId' ]); + const response = await this[method] (this.extend (request, requestParams)); + return this.parseOrder (response, market); + } + + async cancelAllOrders (symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#cancelAllOrders + * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-all-open-orders-on-a-symbol-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-all-open-orders-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-all-open-orders-trade + * @see https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-on-specific-symbol-trade + * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade + * @description cancel all open orders in a market + * @param {string} symbol unified market symbol of the market to cancel orders in + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading + * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const type = this.safeString (params, 'type', market['type']); + params = this.omit (params, [ 'type' ]); + const [ marginMode, query ] = this.handleMarginModeAndParams ('cancelAllOrders', params); + let method = 'privateDeleteOpenOrders'; + if (market['option']) { + method = 'eapiPrivateDeleteAllOpenOrders'; + } else if (market['linear']) { + method = 'fapiPrivateDeleteAllOpenOrders'; + } else if (market['inverse']) { + method = 'dapiPrivateDeleteAllOpenOrders'; + } else if ((type === 'margin') || (marginMode !== undefined)) { + method = 'sapiDeleteMarginOpenOrders'; + if (marginMode === 'isolated') { + request['isIsolated'] = true; + } + } + const response = await this[method] (this.extend (request, query)); + if (Array.isArray (response)) { + return this.parseOrders (response, market); + } else { + return response; + } + } + + async cancelOrders (ids: Int[], symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#cancelOrders + * @description cancel multiple orders + * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-multiple-orders-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-multiple-orders-trade + * @param {string[]} ids order ids + * @param {string} [symbol] unified market symbol + * @param {object} [params] extra parameters specific to the exchange API endpoint + * + * EXCHANGE SPECIFIC PARAMETERS + * @param {string[]} [params.origClientOrderIdList] max length 10 e.g. ["my_id_1","my_id_2"], encode the double quotes. No space after comma + * @param {int[]} [params.recvWindow] + * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' cancelOrders() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + if (!market['contract']) { + throw new BadRequest (this.id + ' cancelOrders is only supported for swap markets.'); + } + const request = { + 'symbol': market['id'], + 'orderidlist': ids, + }; + let response = undefined; + if (market['linear']) { + response = await this.fapiPrivateDeleteBatchOrders (this.extend (request, params)); + } else if (market['inverse']) { + response = await this.dapiPrivateDeleteBatchOrders (this.extend (request, params)); + } + // + // [ + // { + // "clientOrderId": "myOrder1", + // "cumQty": "0", + // "cumQuote": "0", + // "executedQty": "0", + // "orderId": 283194212, + // "origQty": "11", + // "origType": "TRAILING_STOP_MARKET", + // "price": "0", + // "reduceOnly": false, + // "side": "BUY", + // "positionSide": "SHORT", + // "status": "CANCELED", + // "stopPrice": "9300", // please ignore when order type is TRAILING_STOP_MARKET + // "closePosition": false, // if Close-All + // "symbol": "BTCUSDT", + // "timeInForce": "GTC", + // "type": "TRAILING_STOP_MARKET", + // "activatePrice": "9020", // activation price, only return with TRAILING_STOP_MARKET order + // "priceRate": "0.3", // callback rate, only return with TRAILING_STOP_MARKET order + // "updateTime": 1571110484038, + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, // if conditional order trigger is protected + // "priceMatch": "NONE", // price match mode + // "selfTradePreventionMode": "NONE", // self trading preventation mode + // "goodTillDate": 0 // order pre-set auot cancel time for TIF GTD order + // }, + // { + // "code": -2011, + // "msg": "Unknown order sent." + // } + // ] + // + return this.parseOrders (response, market); + } + + async fetchOrderTrades (id: string, symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchOrderTrades + * @description fetch all the trades made from a single order + * @see https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#account-trade-list-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-trade-list-user_data + * @param {string} id order id + * @param {string} symbol unified market symbol + * @param {int} [since] the earliest time in ms to fetch trades for + * @param {int} [limit] the maximum number of trades to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchOrderTrades() requires a symbol argument'); + } + await this.loadMarkets (); + const market = this.market (symbol); + const type = this.safeString (params, 'type', market['type']); + params = this.omit (params, 'type'); + if (type !== 'spot') { + throw new NotSupported (this.id + ' fetchOrderTrades() supports spot markets only'); + } + const request = { + 'orderId': id, + }; + return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params)); + } + + async fetchMyTrades (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchMyTrades + * @description fetch all trades made by the user + * @see https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#account-trade-list-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-trade-list-user_data + * @param {string} symbol unified market symbol + * @param {int} [since] the earliest time in ms to fetch trades for + * @param {int} [limit] the maximum number of trades structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @param {int} [params.until] the latest time in ms to fetch entries for + * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchMyTrades', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchMyTrades', symbol, since, limit, params) as Trade[]; + } + const request = {}; + let market = undefined; + let type = undefined; + let method = undefined; + let marginMode = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + } + [ type, params ] = this.handleMarketTypeAndParams ('fetchMyTrades', market, params); + if (type === 'option') { + method = 'eapiPrivateGetUserTrades'; + } else { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument'); + } + [ marginMode, params ] = this.handleMarginModeAndParams ('fetchMyTrades', params); + if (type === 'spot' || type === 'margin') { + method = 'privateGetMyTrades'; + if ((type === 'margin') || (marginMode !== undefined)) { + method = 'sapiGetMarginMyTrades'; + if (marginMode === 'isolated') { + request['isIsolated'] = true; + } + } + } else if (market['linear']) { + method = 'fapiPrivateGetUserTrades'; + } else if (market['inverse']) { + method = 'dapiPrivateGetUserTrades'; + } + } + let endTime = this.safeInteger2 (params, 'until', 'endTime'); + if (since !== undefined) { + const startTime = since; + request['startTime'] = startTime; + // https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data + // If startTime and endTime are both not sent, then the last 7 days' data will be returned. + // The time between startTime and endTime cannot be longer than 7 days. + // The parameter fromId cannot be sent with startTime or endTime. + const currentTimestamp = this.milliseconds (); + const oneWeek = 7 * 24 * 60 * 60 * 1000; + if ((currentTimestamp - startTime) >= oneWeek) { + if ((endTime === undefined) && market['linear']) { + endTime = this.sum (startTime, oneWeek); + endTime = Math.min (endTime, currentTimestamp); + } + } + } + if (endTime !== undefined) { + request['endTime'] = endTime; + params = this.omit (params, [ 'endTime', 'until' ]); + } + if (limit !== undefined) { + if ((type === 'option') || market['contract']) { + limit = Math.min (limit, 1000); // above 1000, returns error + } + request['limit'] = limit; + } + const response = await this[method] (this.extend (request, params)); + // + // spot trade + // + // [ + // { + // "symbol": "BNBBTC", + // "id": 28457, + // "orderId": 100234, + // "price": "4.00000100", + // "qty": "12.00000000", + // "commission": "10.10000000", + // "commissionAsset": "BNB", + // "time": 1499865549590, + // "isBuyer": true, + // "isMaker": false, + // "isBestMatch": true, + // } + // ] + // + // futures trade + // + // [ + // { + // "accountId": 20, + // "buyer": False, + // "commission": "-0.07819010", + // "commissionAsset": "USDT", + // "counterPartyId": 653, + // "id": 698759, + // "maker": False, + // "orderId": 25851813, + // "price": "7819.01", + // "qty": "0.002", + // "quoteQty": "0.01563", + // "realizedPnl": "-0.91539999", + // "side": "SELL", + // "symbol": "BTCUSDT", + // "time": 1569514978020 + // } + // ] + // + // options (eapi) + // + // [ + // { + // "id": 1125899906844226012, + // "tradeId": 73, + // "orderId": 4638761100843040768, + // "symbol": "ETH-230211-1500-C", + // "price": "18.70000000", + // "quantity": "-0.57000000", + // "fee": "0.17305890", + // "realizedProfit": "-3.53400000", + // "side": "SELL", + // "type": "LIMIT", + // "volatility": "0.30000000", + // "liquidity": "MAKER", + // "time": 1676085216845, + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT" + // } + // ] + // + return this.parseTrades (response, market, since, limit); + } + + async fetchMyDustTrades (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchMyDustTrades + * @description fetch all dust trades made by the user + * @see https://binance-docs.github.io/apidocs/spot/en/#dustlog-user_data + * @param {string} symbol not used by binance fetchMyDustTrades () + * @param {int} [since] the earliest time in ms to fetch my dust trades for + * @param {int} [limit] the maximum number of dust trades to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} + */ + // + // Binance provides an opportunity to trade insignificant (i.e. non-tradable and non-withdrawable) + // token leftovers (of any asset) into `BNB` coin which in turn can be used to pay trading fees with it. + // The corresponding trades history is called the `Dust Log` and can be requested via the following end-point: + // https://github.com/binance-exchange/binance-official-api-docs/blob/master/wapi-api.md#dustlog-user_data + // + await this.loadMarkets (); + const request = {}; + if (since !== undefined) { + request['startTime'] = since; + request['endTime'] = this.sum (since, 7776000000); + } + const response = await this.sapiGetAssetDribblet (this.extend (request, params)); + // { + // "total": "4", + // "userAssetDribblets": [ + // { + // "operateTime": "1627575731000", + // "totalServiceChargeAmount": "0.00001453", + // "totalTransferedAmount": "0.00072693", + // "transId": "70899815863", + // "userAssetDribbletDetails": [ + // { + // "fromAsset": "LTC", + // "amount": "0.000006", + // "transferedAmount": "0.00000267", + // "serviceChargeAmount": "0.00000005", + // "operateTime": "1627575731000", + // "transId": "70899815863" + // }, + // { + // "fromAsset": "GBP", + // "amount": "0.15949157", + // "transferedAmount": "0.00072426", + // "serviceChargeAmount": "0.00001448", + // "operateTime": "1627575731000", + // "transId": "70899815863" + // } + // ] + // }, + // ] + // } + const results = this.safeValue (response, 'userAssetDribblets', []); + const rows = this.safeInteger (response, 'total', 0); + const data = []; + for (let i = 0; i < rows; i++) { + const logs = this.safeValue (results[i], 'userAssetDribbletDetails', []); + for (let j = 0; j < logs.length; j++) { + logs[j]['isDustTrade'] = true; + data.push (logs[j]); + } + } + const trades = this.parseTrades (data, undefined, since, limit); + return this.filterBySinceLimit (trades, since, limit); + } + + parseDustTrade (trade, market: Market = undefined) { + // + // { + // "fromAsset": "USDT", + // "amount": "0.009669", + // "transferedAmount": "0.00002992", + // "serviceChargeAmount": "0.00000059", + // "operateTime": "1628076010000", + // "transId": "71416578712", + // "isDustTrade": true + // } + // + const orderId = this.safeString (trade, 'transId'); + const timestamp = this.safeInteger (trade, 'operateTime'); + const currencyId = this.safeString (trade, 'fromAsset'); + const tradedCurrency = this.safeCurrencyCode (currencyId); + const bnb = this.currency ('BNB'); + const earnedCurrency = bnb['code']; + const applicantSymbol = earnedCurrency + '/' + tradedCurrency; + let tradedCurrencyIsQuote = false; + if (applicantSymbol in this.markets) { + tradedCurrencyIsQuote = true; + } + const feeCostString = this.safeString (trade, 'serviceChargeAmount'); + const fee = { + 'currency': earnedCurrency, + 'cost': this.parseNumber (feeCostString), + }; + let symbol = undefined; + let amountString = undefined; + let costString = undefined; + let side = undefined; + if (tradedCurrencyIsQuote) { + symbol = applicantSymbol; + amountString = this.safeString (trade, 'transferedAmount'); + costString = this.safeString (trade, 'amount'); + side = 'buy'; + } else { + symbol = tradedCurrency + '/' + earnedCurrency; + amountString = this.safeString (trade, 'amount'); + costString = this.safeString (trade, 'transferedAmount'); + side = 'sell'; + } + let priceString = undefined; + if (costString !== undefined) { + if (amountString) { + priceString = Precise.stringDiv (costString, amountString); + } + } + const id = undefined; + const amount = this.parseNumber (amountString); + const price = this.parseNumber (priceString); + const cost = this.parseNumber (costString); + const type = undefined; + const takerOrMaker = undefined; + return { + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'symbol': symbol, + 'order': orderId, + 'type': type, + 'takerOrMaker': takerOrMaker, + 'side': side, + 'amount': amount, + 'price': price, + 'cost': cost, + 'fee': fee, + 'info': trade, + }; + } + + async fetchDeposits (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchDeposits + * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data + * @description fetch all deposits made to an account + * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#deposit-history-supporting-network-user_data + * @param {string} code unified currency code + * @param {int} [since] the earliest time in ms to fetch deposits for + * @param {int} [limit] the maximum number of deposits structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {bool} [params.fiat] if true, only fiat deposits will be returned + * @param {int} [params.until] the latest time in ms to fetch entries for + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchDeposits', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchDeposits', code, since, limit, params); + } + let currency = undefined; + let response = undefined; + const request = {}; + const legalMoney = this.safeValue (this.options, 'legalMoney', {}); + const fiatOnly = this.safeValue (params, 'fiat', false); + params = this.omit (params, 'fiatOnly'); + const until = this.safeInteger (params, 'until'); + params = this.omit (params, 'until'); + if (fiatOnly || (code in legalMoney)) { + if (code !== undefined) { + currency = this.currency (code); + } + request['transactionType'] = 0; + if (since !== undefined) { + request['beginTime'] = since; + } + if (until !== undefined) { + request['endTime'] = until; + } + const raw = await this.sapiGetFiatOrders (this.extend (request, params)); + response = this.safeValue (raw, 'data'); + // { + // "code": "000000", + // "message": "success", + // "data": [ + // { + // "orderNo": "25ced37075c1470ba8939d0df2316e23", + // "fiatCurrency": "EUR", + // "indicatedAmount": "15.00", + // "amount": "15.00", + // "totalFee": "0.00", + // "method": "card", + // "status": "Failed", + // "createTime": 1627501026000, + // "updateTime": 1627501027000 + // } + // ], + // "total": 1, + // "success": true + // } + } else { + if (code !== undefined) { + currency = this.currency (code); + request['coin'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + // max 3 months range https://github.com/ccxt/ccxt/issues/6495 + let endTime = this.sum (since, 7776000000); + if (until !== undefined) { + endTime = Math.min (endTime, until); + } + request['endTime'] = endTime; + } + if (limit !== undefined) { + request['limit'] = limit; + } + response = await this.sapiGetCapitalDepositHisrec (this.extend (request, params)); + // [ + // { + // "amount": "0.01844487", + // "coin": "BCH", + // "network": "BCH", + // "status": 1, + // "address": "1NYxAJhW2281HK1KtJeaENBqHeygA88FzR", + // "addressTag": "", + // "txId": "bafc5902504d6504a00b7d0306a41154cbf1d1b767ab70f3bc226327362588af", + // "insertTime": 1610784980000, + // "transferType": 0, + // "confirmTimes": "2/2" + // }, + // { + // "amount": "4500", + // "coin": "USDT", + // "network": "BSC", + // "status": 1, + // "address": "0xc9c923c87347ca0f3451d6d308ce84f691b9f501", + // "addressTag": "", + // "txId": "Internal transfer 51376627901", + // "insertTime": 1618394381000, + // "transferType": 1, + // "confirmTimes": "1/15" + // } + // ] + } + for (let i = 0; i < response.length; i++) { + response[i]['type'] = 'deposit'; + } + return this.parseTransactions (response, currency, since, limit); + } + + async fetchWithdrawals (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name binance#fetchWithdrawals + * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data + * @description fetch all withdrawals made from an account + * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data + * @param {string} code unified currency code + * @param {int} [since] the earliest time in ms to fetch withdrawals for + * @param {int} [limit] the maximum number of withdrawals structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {bool} [params.fiat] if true, only fiat withdrawals will be returned + * @param {int} [params.until] the latest time in ms to fetch withdrawals for + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchWithdrawals', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchWithdrawals', code, since, limit, params); + } + const legalMoney = this.safeValue (this.options, 'legalMoney', {}); + const fiatOnly = this.safeValue (params, 'fiat', false); + params = this.omit (params, 'fiatOnly'); + const request = {}; + const until = this.safeInteger (params, 'until'); + if (until !== undefined) { + params = this.omit (params, 'until'); + request['endTime'] = until; + } + let response = undefined; + let currency = undefined; + if (fiatOnly || (code in legalMoney)) { + if (code !== undefined) { + currency = this.currency (code); + } + request['transactionType'] = 1; + if (since !== undefined) { + request['beginTime'] = since; + } + const raw = await this.sapiGetFiatOrders (this.extend (request, params)); + response = this.safeValue (raw, 'data'); + // { + // "code": "000000", + // "message": "success", + // "data": [ + // { + // "orderNo": "CJW706452266115170304", + // "fiatCurrency": "GBP", + // "indicatedAmount": "10001.50", + // "amount": "100.00", + // "totalFee": "1.50", + // "method": "bank transfer", + // "status": "Successful", + // "createTime": 1620037745000, + // "updateTime": 1620038480000 + // }, + // { + // "orderNo": "CJW706287492781891584", + // "fiatCurrency": "GBP", + // "indicatedAmount": "10001.50", + // "amount": "100.00", + // "totalFee": "1.50", + // "method": "bank transfer", + // "status": "Successful", + // "createTime": 1619998460000, + // "updateTime": 1619998823000 + // } + // ], + // "total": 39, + // "success": true + // } + } else { + if (code !== undefined) { + currency = this.currency (code); + request['coin'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + // max 3 months range https://github.com/ccxt/ccxt/issues/6495 + request['endTime'] = this.sum (since, 7776000000); + } + if (limit !== undefined) { + request['limit'] = limit; + } + response = await this.sapiGetCapitalWithdrawHistory (this.extend (request, params)); + // [ + // { + // "id": "69e53ad305124b96b43668ceab158a18", + // "amount": "28.75", + // "transactionFee": "0.25", + // "coin": "XRP", + // "status": 6, + // "address": "r3T75fuLjX51mmfb5Sk1kMNuhBgBPJsjza", + // "addressTag": "101286922", + // "txId": "19A5B24ED0B697E4F0E9CD09FCB007170A605BC93C9280B9E6379C5E6EF0F65A", + // "applyTime": "2021-04-15 12:09:16", + // "network": "XRP", + // "transferType": 0 + // }, + // { + // "id": "9a67628b16ba4988ae20d329333f16bc", + // "amount": "20", + // "transactionFee": "20", + // "coin": "USDT", + // "status": 6, + // "address": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1", + // "txId": "0x77fbf2cf2c85b552f0fd31fd2e56dc95c08adae031d96f3717d8b17e1aea3e46", + // "applyTime": "2021-04-15 12:06:53", + // "network": "ETH", + // "transferType": 0 + // }, + // { + // "id": "a7cdc0afbfa44a48bd225c9ece958fe2", + // "amount": "51", + // "transactionFee": "1", + // "coin": "USDT", + // "status": 6, + // "address": "TYDmtuWL8bsyjvcauUTerpfYyVhFtBjqyo", + // "txId": "168a75112bce6ceb4823c66726ad47620ad332e69fe92d9cb8ceb76023f9a028", + // "applyTime": "2021-04-13 12:46:59", + // "network": "TRX", + // "transferType": 0 + // } + // ] + } + for (let i = 0; i < response.length; i++) { + response[i]['type'] = 'withdrawal'; + } + return this.parseTransactions (response, currency, since, limit); + } + + parseTransactionStatusByType (status, type = undefined) { + const statusesByType = { + 'deposit': { + '0': 'pending', + '1': 'ok', + '6': 'ok', + // Fiat + // Processing, Failed, Successful, Finished, Refunding, Refunded, Refund Failed, Order Partial credit Stopped + 'Processing': 'pending', + 'Failed': 'failed', + 'Successful': 'ok', + 'Refunding': 'canceled', + 'Refunded': 'canceled', + 'Refund Failed': 'failed', + }, + 'withdrawal': { + '0': 'pending', // Email Sent + '1': 'canceled', // Cancelled (different from 1 = ok in deposits) + '2': 'pending', // Awaiting Approval + '3': 'failed', // Rejected + '4': 'pending', // Processing + '5': 'failed', // Failure + '6': 'ok', // Completed + // Fiat + // Processing, Failed, Successful, Finished, Refunding, Refunded, Refund Failed, Order Partial credit Stopped + 'Processing': 'pending', + 'Failed': 'failed', + 'Successful': 'ok', + 'Refunding': 'canceled', + 'Refunded': 'canceled', + 'Refund Failed': 'failed', + }, + }; + const statuses = this.safeValue (statusesByType, type, {}); + return this.safeString (statuses, status, status); + } + + parseTransaction (transaction, currency: Currency = undefined): Transaction { + // + // fetchDeposits + // + // { + // "amount": "4500", + // "coin": "USDT", + // "network": "BSC", + // "status": 1, + // "address": "0xc9c923c87347ca0f3451d6d308ce84f691b9f501", + // "addressTag": "", + // "txId": "Internal transfer 51376627901", + // "insertTime": 1618394381000, + // "transferType": 1, + // "confirmTimes": "1/15" + // } + // + // fetchWithdrawals + // + // { + // "id": "69e53ad305124b96b43668ceab158a18", + // "amount": "28.75", + // "transactionFee": "0.25", + // "coin": "XRP", + // "status": 6, + // "address": "r3T75fuLjX51mmfb5Sk1kMNuhBgBPJsjza", + // "addressTag": "101286922", + // "txId": "19A5B24ED0B697E4F0E9CD09FCB007170A605BC93C9280B9E6379C5E6EF0F65A", + // "applyTime": "2021-04-15 12:09:16", + // "network": "XRP", + // "transferType": 0 + // } + // + // fiat transaction + // withdraw + // { + // "orderNo": "CJW684897551397171200", + // "fiatCurrency": "GBP", + // "indicatedAmount": "29.99", + // "amount": "28.49", + // "totalFee": "1.50", + // "method": "bank transfer", + // "status": "Successful", + // "createTime": 1614898701000, + // "updateTime": 1614898820000 + // } + // + // deposit + // { + // "orderNo": "25ced37075c1470ba8939d0df2316e23", + // "fiatCurrency": "EUR", + // "transactionType": 0, + // "indicatedAmount": "15.00", + // "amount": "15.00", + // "totalFee": "0.00", + // "method": "card", + // "status": "Failed", + // "createTime": "1627501026000", + // "updateTime": "1627501027000" + // } + // + // withdraw + // + // { id: "9a67628b16ba4988ae20d329333f16bc" } + // + const id = this.safeString2 (transaction, 'id', 'orderNo'); + const address = this.safeString (transaction, 'address'); + let tag = this.safeString (transaction, 'addressTag'); // set but unused + if (tag !== undefined) { + if (tag.length < 1) { + tag = undefined; + } + } + let txid = this.safeString (transaction, 'txId'); + if ((txid !== undefined) && (txid.indexOf ('Internal transfer ') >= 0)) { + txid = txid.slice (18); + } + const currencyId = this.safeString2 (transaction, 'coin', 'fiatCurrency'); + let code = this.safeCurrencyCode (currencyId, currency); + let timestamp = undefined; + timestamp = this.safeInteger2 (transaction, 'insertTime', 'createTime'); + if (timestamp === undefined) { + timestamp = this.parse8601 (this.safeString (transaction, 'applyTime')); + } + const updated = this.safeInteger2 (transaction, 'successTime', 'updateTime'); + let type = this.safeString (transaction, 'type'); + if (type === undefined) { + const txType = this.safeString (transaction, 'transactionType'); + if (txType !== undefined) { + type = (txType === '0') ? 'deposit' : 'withdrawal'; + } + const legalMoneyCurrenciesById = this.safeValue (this.options, 'legalMoneyCurrenciesById'); + code = this.safeString (legalMoneyCurrenciesById, code, code); + } + const status = this.parseTransactionStatusByType (this.safeString (transaction, 'status'), type); + const amount = this.safeNumber (transaction, 'amount'); + const feeCost = this.safeNumber2 (transaction, 'transactionFee', 'totalFee'); + let fee = undefined; + if (feeCost !== undefined) { + fee = { 'currency': code, 'cost': feeCost }; + } + const internalInteger = this.safeInteger (transaction, 'transferType'); + let internal = undefined; + if (internalInteger !== undefined) { + internal = internalInteger ? true : false; + } + const network = this.safeString (transaction, 'network'); + return { + 'info': transaction, + 'id': id, + 'txid': txid, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'network': network, + 'address': address, + 'addressTo': address, + 'addressFrom': undefined, + 'tag': tag, + 'tagTo': tag, + 'tagFrom': undefined, + 'type': type, + 'amount': amount, + 'currency': code, + 'status': status, + 'updated': updated, + 'internal': internal, + 'comment': undefined, + 'fee': fee, + }; + } + + parseTransferStatus (status) { + const statuses = { + 'CONFIRMED': 'ok', + }; + return this.safeString (statuses, status, status); + } + + parseTransfer (transfer, currency: Currency = undefined) { + // + // transfer + // + // { + // "tranId":13526853623 + // } + // + // fetchTransfers + // + // { + // "timestamp": 1614640878000, + // "asset": "USDT", + // "amount": "25", + // "type": "MAIN_UMFUTURE", + // "status": "CONFIRMED", + // "tranId": 43000126248 + // } + // + const id = this.safeString (transfer, 'tranId'); + const currencyId = this.safeString (transfer, 'asset'); + const code = this.safeCurrencyCode (currencyId, currency); + const amount = this.safeNumber (transfer, 'amount'); + const type = this.safeString (transfer, 'type'); + let fromAccount = undefined; + let toAccount = undefined; + const accountsById = this.safeValue (this.options, 'accountsById', {}); + if (type !== undefined) { + const parts = type.split ('_'); + fromAccount = this.safeValue (parts, 0); + toAccount = this.safeValue (parts, 1); + fromAccount = this.safeString (accountsById, fromAccount, fromAccount); + toAccount = this.safeString (accountsById, toAccount, toAccount); + } + const timestamp = this.safeInteger (transfer, 'timestamp'); + const status = this.parseTransferStatus (this.safeString (transfer, 'status')); + return { + 'info': transfer, + 'id': id, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'currency': code, + 'amount': amount, + 'fromAccount': fromAccount, + 'toAccount': toAccount, + 'status': status, + }; + } + + parseIncome (income, market: Market = undefined) { + // + // { + // "symbol": "ETHUSDT", + // "incomeType": "FUNDING_FEE", + // "income": "0.00134317", + // "asset": "USDT", + // "time": "1621584000000", + // "info": "FUNDING_FEE", + // "tranId": "4480321991774044580", + // "tradeId": "" + // } + // + const marketId = this.safeString (income, 'symbol'); + const symbol = this.safeSymbol (marketId, market, undefined, 'swap'); + const amount = this.safeNumber (income, 'income'); + const currencyId = this.safeString (income, 'asset'); + const code = this.safeCurrencyCode (currencyId); + const id = this.safeString (income, 'tranId'); + const timestamp = this.safeInteger (income, 'time'); + return { + 'info': income, + 'symbol': symbol, + 'code': code, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'id': id, + 'amount': amount, + }; + } + + async transfer (code: string, amount, fromAccount, toAccount, params = {}) { + /** + * @method + * @name binance#transfer + * @description transfer currency internally between wallets on the same account + * @see https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer-user_data + * @see https://binance-docs.github.io/apidocs/spot/en/#isolated-margin-account-transfer-margin + * @param {string} code unified currency code + * @param {float} amount amount to transfer + * @param {string} fromAccount account to transfer from + * @param {string} toAccount account to transfer to + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + 'amount': this.currencyToPrecision (code, amount), + }; + request['type'] = this.safeString (params, 'type'); + let method = 'sapiPostAssetTransfer'; + if (request['type'] === undefined) { + const symbol = this.safeString (params, 'symbol'); + if (symbol !== undefined) { + params = this.omit (params, 'symbol'); + } + let fromId = this.convertTypeToAccount (fromAccount).toUpperCase (); + let toId = this.convertTypeToAccount (toAccount).toUpperCase (); + if (fromId === 'ISOLATED') { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' transfer () requires params["symbol"] when fromAccount is ' + fromAccount); + } else { + fromId = this.marketId (symbol); + } + } + if (toId === 'ISOLATED') { + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' transfer () requires params["symbol"] when toAccount is ' + toAccount); + } else { + toId = this.marketId (symbol); + } + } + const accountsById = this.safeValue (this.options, 'accountsById', {}); + const fromIsolated = !(fromId in accountsById); + const toIsolated = !(toId in accountsById); + if (fromIsolated || toIsolated) { // Isolated margin transfer + const fromFuture = fromId === 'UMFUTURE' || fromId === 'CMFUTURE'; + const toFuture = toId === 'UMFUTURE' || toId === 'CMFUTURE'; + const fromSpot = fromId === 'MAIN'; + const toSpot = toId === 'MAIN'; + const funding = fromId === 'FUNDING' || toId === 'FUNDING'; + const mining = fromId === 'MINING' || toId === 'MINING'; + const option = fromId === 'OPTION' || toId === 'OPTION'; + const prohibitedWithIsolated = fromFuture || toFuture || mining || funding || option; + if ((fromIsolated || toIsolated) && prohibitedWithIsolated) { + throw new BadRequest (this.id + ' transfer () does not allow transfers between ' + fromAccount + ' and ' + toAccount); + } else if (toSpot && fromIsolated) { + method = 'sapiPostMarginIsolatedTransfer'; + request['transFrom'] = 'ISOLATED_MARGIN'; + request['transTo'] = 'SPOT'; + request['symbol'] = fromId; + } else if (fromSpot && toIsolated) { + method = 'sapiPostMarginIsolatedTransfer'; + request['transFrom'] = 'SPOT'; + request['transTo'] = 'ISOLATED_MARGIN'; + request['symbol'] = toId; + } else { + if (fromIsolated) { + request['fromSymbol'] = fromId; + fromId = 'ISOLATEDMARGIN'; + } + if (toIsolated) { + request['toSymbol'] = toId; + toId = 'ISOLATEDMARGIN'; + } + request['type'] = fromId + '_' + toId; + } + } else { + request['type'] = fromId + '_' + toId; + } + } + params = this.omit (params, 'type'); + const response = await this[method] (this.extend (request, params)); + // + // { + // "tranId":13526853623 + // } + // + return this.parseTransfer (response, currency); + } + + async fetchTransfers (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchTransfers + * @see https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer-user_data + * @description fetch a history of internal transfers made on an account + * @see https://binance-docs.github.io/apidocs/spot/en/#query-user-universal-transfer-history-user_data + * @param {string} code unified currency code of the currency transferred + * @param {int} [since] the earliest time in ms to fetch transfers for + * @param {int} [limit] the maximum number of transfers structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {int} [params.until] the latest time in ms to fetch transfers for + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchTransfers', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchTransfers', code, since, limit, params); + } + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + } + const defaultType = this.safeString2 (this.options, 'fetchTransfers', 'defaultType', 'spot'); + const fromAccount = this.safeString (params, 'fromAccount', defaultType); + const defaultTo = (fromAccount === 'future') ? 'spot' : 'future'; + const toAccount = this.safeString (params, 'toAccount', defaultTo); + let type = this.safeString (params, 'type'); + const accountsByType = this.safeValue (this.options, 'accountsByType', {}); + const fromId = this.safeString (accountsByType, fromAccount); + const toId = this.safeString (accountsByType, toAccount); + if (type === undefined) { + if (fromId === undefined) { + const keys = Object.keys (accountsByType); + throw new ExchangeError (this.id + ' fromAccount parameter must be one of ' + keys.join (', ')); + } + if (toId === undefined) { + const keys = Object.keys (accountsByType); + throw new ExchangeError (this.id + ' toAccount parameter must be one of ' + keys.join (', ')); + } + type = fromId + '_' + toId; + } + const request = { + 'type': type, + }; + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['size'] = limit; + } + const until = this.safeInteger (params, 'until'); + if (until !== undefined) { + params = this.omit (params, 'until'); + request['endTime'] = until; + } + const response = await this.sapiGetAssetTransfer (this.extend (request, params)); + // + // { + // "total": 3, + // "rows": [ + // { + // "timestamp": 1614640878000, + // "asset": "USDT", + // "amount": "25", + // "type": "MAIN_UMFUTURE", + // "status": "CONFIRMED", + // "tranId": 43000126248 + // }, + // ] + // } + // + const rows = this.safeValue (response, 'rows', []); + return this.parseTransfers (rows, currency, since, limit); + } + + async fetchDepositAddress (code: string, params = {}) { + /** + * @method + * @name binance#fetchDepositAddress + * @description fetch the deposit address for a currency associated with this account + * @see https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data + * @param {string} code unified currency code + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'coin': currency['id'], + // 'network': 'ETH', // 'BSC', 'XMR', you can get network and isDefault in networkList in the response of sapiGetCapitalConfigDetail + }; + const networks = this.safeValue (this.options, 'networks', {}); + let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH + network = this.safeString (networks, network, network); // handle ERC20>ETH alias + if (network !== undefined) { + request['network'] = network; + params = this.omit (params, 'network'); + } + // has support for the 'network' parameter + // https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data + const response = await this.sapiGetCapitalDepositAddress (this.extend (request, params)); + // + // { + // "currency": "XRP", + // "address": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh", + // "tag": "108618262", + // "info": { + // "coin": "XRP", + // "address": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh", + // "tag": "108618262", + // "url": "https://bithomp.com/explorer/rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh" + // } + // } + // + const address = this.safeString (response, 'address'); + const url = this.safeString (response, 'url'); + let impliedNetwork = undefined; + if (url !== undefined) { + const reverseNetworks = this.safeValue (this.options, 'reverseNetworks', {}); + const parts = url.split ('/'); + let topLevel = this.safeString (parts, 2); + if ((topLevel === 'blockchair.com') || (topLevel === 'viewblock.io')) { + const subLevel = this.safeString (parts, 3); + if (subLevel !== undefined) { + topLevel = topLevel + '/' + subLevel; + } + } + impliedNetwork = this.safeString (reverseNetworks, topLevel); + const impliedNetworks = this.safeValue (this.options, 'impliedNetworks', { + 'ETH': { 'ERC20': 'ETH' }, + 'TRX': { 'TRC20': 'TRX' }, + }); + if (code in impliedNetworks) { + const conversion = this.safeValue (impliedNetworks, code, {}); + impliedNetwork = this.safeString (conversion, impliedNetwork, impliedNetwork); + } + } + let tag = this.safeString (response, 'tag', ''); + if (tag.length === 0) { + tag = undefined; + } + this.checkAddress (address); + return { + 'currency': code, + 'address': address, + 'tag': tag, + 'network': impliedNetwork, + 'info': response, + }; + } + + async fetchTransactionFees (codes = undefined, params = {}) { + /** + * @method + * @name binance#fetchTransactionFees + * @deprecated + * @description please use fetchDepositWithdrawFees instead + * @see https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data + * @param {string[]|undefined} codes not used by binance fetchTransactionFees () + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} + */ + await this.loadMarkets (); + const response = await this.sapiGetCapitalConfigGetall (params); + // + // [ + // { + // "coin": "BAT", + // "depositAllEnable": true, + // "withdrawAllEnable": true, + // "name": "Basic Attention Token", + // "free": "0", + // "locked": "0", + // "freeze": "0", + // "withdrawing": "0", + // "ipoing": "0", + // "ipoable": "0", + // "storage": "0", + // "isLegalMoney": false, + // "trading": true, + // "networkList": [ + // { + // "network": "BNB", + // "coin": "BAT", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": false, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": '', + // "withdrawDesc": '', + // "specialTips": "The name of this asset is Basic Attention Token (BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.", + // "name": "BEP2", + // "resetAddressStatus": false, + // "addressRegex": "^(bnb1)[0-9a-z]{38}$", + // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", + // "withdrawFee": "0.27", + // "withdrawMin": "0.54", + // "withdrawMax": "10000000000", + // "minConfirm": "1", + // "unLockConfirm": "0" + // }, + // { + // "network": "BSC", + // "coin": "BAT", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": false, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": '', + // "withdrawDesc": '', + // "specialTips": "The name of this asset is Basic Attention Token. Please ensure you are depositing Basic Attention Token (BAT) tokens under the contract address ending in 9766e.", + // "name": "BEP20 (BSC)", + // "resetAddressStatus": false, + // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", + // "memoRegex": '', + // "withdrawFee": "0.27", + // "withdrawMin": "0.54", + // "withdrawMax": "10000000000", + // "minConfirm": "15", + // "unLockConfirm": "0" + // }, + // { + // "network": "ETH", + // "coin": "BAT", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": true, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": '', + // "withdrawDesc": '', + // "specialTips": "The name of this asset is Basic Attention Token. Please ensure you are depositing Basic Attention Token (BAT) tokens under the contract address ending in 887ef.", + // "name": "ERC20", + // "resetAddressStatus": false, + // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", + // "memoRegex": '', + // "withdrawFee": "27", + // "withdrawMin": "54", + // "withdrawMax": "10000000000", + // "minConfirm": "12", + // "unLockConfirm": "0" + // } + // ] + // } + // ] + // + const withdrawFees = {}; + for (let i = 0; i < response.length; i++) { + const entry = response[i]; + const currencyId = this.safeString (entry, 'coin'); + const code = this.safeCurrencyCode (currencyId); + const networkList = this.safeValue (entry, 'networkList', []); + withdrawFees[code] = {}; + for (let j = 0; j < networkList.length; j++) { + const networkEntry = networkList[j]; + const networkId = this.safeString (networkEntry, 'network'); + const networkCode = this.safeCurrencyCode (networkId); + const fee = this.safeNumber (networkEntry, 'withdrawFee'); + withdrawFees[code][networkCode] = fee; + } + } + return { + 'withdraw': withdrawFees, + 'deposit': {}, + 'info': response, + }; + } + + async fetchDepositWithdrawFees (codes: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchDepositWithdrawFees + * @description fetch deposit and withdraw fees + * @see https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data + * @param {string[]|undefined} codes not used by binance fetchDepositWithdrawFees () + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} + */ + await this.loadMarkets (); + const response = await this.sapiGetCapitalConfigGetall (params); + // + // [ + // { + // "coin": "BAT", + // "depositAllEnable": true, + // "withdrawAllEnable": true, + // "name": "Basic Attention Token", + // "free": "0", + // "locked": "0", + // "freeze": "0", + // "withdrawing": "0", + // "ipoing": "0", + // "ipoable": "0", + // "storage": "0", + // "isLegalMoney": false, + // "trading": true, + // "networkList": [ + // { + // "network": "BNB", + // "coin": "BAT", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": false, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": '', + // "withdrawDesc": '', + // "specialTips": "The name of this asset is Basic Attention Token (BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.", + // "name": "BEP2", + // "resetAddressStatus": false, + // "addressRegex": "^(bnb1)[0-9a-z]{38}$", + // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", + // "withdrawFee": "0.27", + // "withdrawMin": "0.54", + // "withdrawMax": "10000000000", + // "minConfirm": "1", + // "unLockConfirm": "0" + // }, + // ... + // ] + // } + // ] + // + return this.parseDepositWithdrawFees (response, codes, 'coin'); + } + + parseDepositWithdrawFee (fee, currency: Currency = undefined) { + // + // { + // "coin": "BAT", + // "depositAllEnable": true, + // "withdrawAllEnable": true, + // "name": "Basic Attention Token", + // "free": "0", + // "locked": "0", + // "freeze": "0", + // "withdrawing": "0", + // "ipoing": "0", + // "ipoable": "0", + // "storage": "0", + // "isLegalMoney": false, + // "trading": true, + // "networkList": [ + // { + // "network": "BNB", + // "coin": "BAT", + // "withdrawIntegerMultiple": "0.00000001", + // "isDefault": false, + // "depositEnable": true, + // "withdrawEnable": true, + // "depositDesc": '', + // "withdrawDesc": '', + // "specialTips": "The name of this asset is Basic Attention Token (BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.", + // "name": "BEP2", + // "resetAddressStatus": false, + // "addressRegex": "^(bnb1)[0-9a-z]{38}$", + // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", + // "withdrawFee": "0.27", + // "withdrawMin": "0.54", + // "withdrawMax": "10000000000", + // "minConfirm": "1", + // "unLockConfirm": "0" + // }, + // ... + // ] + // } + // + const networkList = this.safeValue (fee, 'networkList', []); + const result = this.depositWithdrawFee (fee); + for (let j = 0; j < networkList.length; j++) { + const networkEntry = networkList[j]; + const networkId = this.safeString (networkEntry, 'network'); + const networkCode = this.networkIdToCode (networkId); + const withdrawFee = this.safeNumber (networkEntry, 'withdrawFee'); + const isDefault = this.safeValue (networkEntry, 'isDefault'); + if (isDefault === true) { + result['withdraw'] = { + 'fee': withdrawFee, + 'percentage': undefined, + }; + } + result['networks'][networkCode] = { + 'withdraw': { + 'fee': withdrawFee, + 'percentage': undefined, + }, + 'deposit': { + 'fee': undefined, + 'percentage': undefined, + }, + }; + } + return result; + } + + async withdraw (code: string, amount, address, tag = undefined, params = {}) { + /** + * @method + * @name binance#withdraw + * @description make a withdrawal + * @see https://binance-docs.github.io/apidocs/spot/en/#withdraw-user_data + * @param {string} code unified currency code + * @param {float} amount the amount to withdraw + * @param {string} address the address to withdraw to + * @param {string} tag + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure} + */ + [ tag, params ] = this.handleWithdrawTagAndParams (tag, params); + this.checkAddress (address); + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'coin': currency['id'], + 'address': address, + 'amount': amount, + // https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi + // issue sapiGetCapitalConfigGetall () to get networks for withdrawing USDT ERC20 vs USDT Omni + // 'network': 'ETH', // 'BTC', 'TRX', etc, optional + }; + if (tag !== undefined) { + request['addressTag'] = tag; + } + const networks = this.safeValue (this.options, 'networks', {}); + let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH + network = this.safeString (networks, network, network); // handle ERC20>ETH alias + if (network !== undefined) { + request['network'] = network; + params = this.omit (params, 'network'); + } + const response = await this.sapiPostCapitalWithdrawApply (this.extend (request, params)); + // { id: '9a67628b16ba4988ae20d329333f16bc' } + return this.parseTransaction (response, currency); + } + + parseTradingFee (fee, market: Market = undefined) { + // + // spot + // [ + // { + // "symbol": "BTCUSDT", + // "makerCommission": "0.001", + // "takerCommission": "0.001" + // } + // ] + // + // swap + // { + // "symbol": "BTCUSD_PERP", + // "makerCommissionRate": "0.00015", // 0.015% + // "takerCommissionRate": "0.00040" // 0.040% + // } + // + const marketId = this.safeString (fee, 'symbol'); + const symbol = this.safeSymbol (marketId, market, undefined, 'spot'); + return { + 'info': fee, + 'symbol': symbol, + 'maker': this.safeNumber2 (fee, 'makerCommission', 'makerCommissionRate'), + 'taker': this.safeNumber2 (fee, 'takerCommission', 'takerCommissionRate'), + }; + } + + async fetchTradingFee (symbol: string, params = {}) { + /** + * @method + * @name binance#fetchTradingFee + * @description fetch the trading fees for a market + * @see https://binance-docs.github.io/apidocs/spot/en/#trade-fee-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#user-commission-rate-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#user-commission-rate-user_data + * @param {string} symbol unified market symbol + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const defaultType = this.safeString2 (this.options, 'fetchTradingFee', 'defaultType', 'linear'); + const type = this.safeString (params, 'type', defaultType); + params = this.omit (params, 'type'); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchTradingFee', market, params); + const isSpotOrMargin = (type === 'spot') || (type === 'margin'); + const isLinear = this.isLinear (type, subType); + const isInverse = this.isInverse (type, subType); + const request = { + 'symbol': market['id'], + }; + let response = undefined; + if (isSpotOrMargin) { + response = await this.sapiGetAssetTradeFee (this.extend (request, params)); + } else if (isLinear) { + response = await this.fapiPrivateGetCommissionRate (this.extend (request, params)); + } else if (isInverse) { + response = await this.dapiPrivateGetCommissionRate (this.extend (request, params)); + } + // + // spot + // [ + // { + // "symbol": "BTCUSDT", + // "makerCommission": "0.001", + // "takerCommission": "0.001" + // } + // ] + // + // swap + // { + // "symbol": "BTCUSD_PERP", + // "makerCommissionRate": "0.00015", // 0.015% + // "takerCommissionRate": "0.00040" // 0.040% + // } + // + let data = response; + if (Array.isArray (data)) { + data = this.safeValue (data, 0, {}); + } + return this.parseTradingFee (data); + } + + async fetchTradingFees (params = {}) { + /** + * @method + * @name binance#fetchTradingFees + * @description fetch the trading fees for multiple markets + * @see https://binance-docs.github.io/apidocs/spot/en/#trade-fee-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols + */ + await this.loadMarkets (); + let method = undefined; + let type = undefined; + [ type, params ] = this.handleMarketTypeAndParams ('fetchTradingFees', undefined, params); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchTradingFees', undefined, params, 'linear'); + const isSpotOrMargin = (type === 'spot') || (type === 'margin'); + const isLinear = this.isLinear (type, subType); + const isInverse = this.isInverse (type, subType); + if (isSpotOrMargin) { + method = 'sapiGetAssetTradeFee'; + } else if (isLinear) { + method = 'fapiPrivateV2GetAccount'; + } else if (isInverse) { + method = 'dapiPrivateGetAccount'; + } + const response = await this[method] (params); + // + // sapi / spot + // + // [ + // { + // "symbol": "ZRXBNB", + // "makerCommission": "0.001", + // "takerCommission": "0.001" + // }, + // { + // "symbol": "ZRXBTC", + // "makerCommission": "0.001", + // "takerCommission": "0.001" + // }, + // ] + // + // fapi / future / linear + // + // { + // "feeTier": 0, // account commisssion tier + // "canTrade": true, // if can trade + // "canDeposit": true, // if can transfer in asset + // "canWithdraw": true, // if can transfer out asset + // "updateTime": 0, + // "totalInitialMargin": "0.00000000", // total initial margin required with current mark price (useless with isolated positions), only for USDT asset + // "totalMaintMargin": "0.00000000", // total maintenance margin required, only for USDT asset + // "totalWalletBalance": "23.72469206", // total wallet balance, only for USDT asset + // "totalUnrealizedProfit": "0.00000000", // total unrealized profit, only for USDT asset + // "totalMarginBalance": "23.72469206", // total margin balance, only for USDT asset + // "totalPositionInitialMargin": "0.00000000", // initial margin required for positions with current mark price, only for USDT asset + // "totalOpenOrderInitialMargin": "0.00000000", // initial margin required for open orders with current mark price, only for USDT asset + // "totalCrossWalletBalance": "23.72469206", // crossed wallet balance, only for USDT asset + // "totalCrossUnPnl": "0.00000000", // unrealized profit of crossed positions, only for USDT asset + // "availableBalance": "23.72469206", // available balance, only for USDT asset + // "maxWithdrawAmount": "23.72469206" // maximum amount for transfer out, only for USDT asset + // ... + // } + // + // dapi / delivery / inverse + // + // { + // "canDeposit": true, + // "canTrade": true, + // "canWithdraw": true, + // "feeTier": 2, + // "updateTime": 0 + // } + // + if (isSpotOrMargin) { + // + // [ + // { + // "symbol": "ZRXBNB", + // "makerCommission": "0.001", + // "takerCommission": "0.001" + // }, + // { + // "symbol": "ZRXBTC", + // "makerCommission": "0.001", + // "takerCommission": "0.001" + // }, + // ] + // + const result = {}; + for (let i = 0; i < response.length; i++) { + const fee = this.parseTradingFee (response[i]); + const symbol = fee['symbol']; + result[symbol] = fee; + } + return result; + } else if (isLinear) { + // + // { + // "feeTier": 0, // account commisssion tier + // "canTrade": true, // if can trade + // "canDeposit": true, // if can transfer in asset + // "canWithdraw": true, // if can transfer out asset + // "updateTime": 0, + // "totalInitialMargin": "0.00000000", // total initial margin required with current mark price (useless with isolated positions), only for USDT asset + // "totalMaintMargin": "0.00000000", // total maintenance margin required, only for USDT asset + // "totalWalletBalance": "23.72469206", // total wallet balance, only for USDT asset + // "totalUnrealizedProfit": "0.00000000", // total unrealized profit, only for USDT asset + // "totalMarginBalance": "23.72469206", // total margin balance, only for USDT asset + // "totalPositionInitialMargin": "0.00000000", // initial margin required for positions with current mark price, only for USDT asset + // "totalOpenOrderInitialMargin": "0.00000000", // initial margin required for open orders with current mark price, only for USDT asset + // "totalCrossWalletBalance": "23.72469206", // crossed wallet balance, only for USDT asset + // "totalCrossUnPnl": "0.00000000", // unrealized profit of crossed positions, only for USDT asset + // "availableBalance": "23.72469206", // available balance, only for USDT asset + // "maxWithdrawAmount": "23.72469206" // maximum amount for transfer out, only for USDT asset + // ... + // } + // + const symbols = Object.keys (this.markets); + const result = {}; + const feeTier = this.safeInteger (response, 'feeTier'); + const feeTiers = this.fees['linear']['trading']['tiers']; + const maker = feeTiers['maker'][feeTier][1]; + const taker = feeTiers['taker'][feeTier][1]; + for (let i = 0; i < symbols.length; i++) { + const symbol = symbols[i]; + const market = this.markets[symbol]; + if (market['linear']) { + result[symbol] = { + 'info': { + 'feeTier': feeTier, + }, + 'symbol': symbol, + 'maker': maker, + 'taker': taker, + }; + } + } + return result; + } else if (isInverse) { + // + // { + // "canDeposit": true, + // "canTrade": true, + // "canWithdraw": true, + // "feeTier": 2, + // "updateTime": 0 + // } + // + const symbols = Object.keys (this.markets); + const result = {}; + const feeTier = this.safeInteger (response, 'feeTier'); + const feeTiers = this.fees['inverse']['trading']['tiers']; + const maker = feeTiers['maker'][feeTier][1]; + const taker = feeTiers['taker'][feeTier][1]; + for (let i = 0; i < symbols.length; i++) { + const symbol = symbols[i]; + const market = this.markets[symbol]; + if (market['inverse']) { + result[symbol] = { + 'info': { + 'feeTier': feeTier, + }, + 'symbol': symbol, + 'maker': maker, + 'taker': taker, + }; + } + } + return result; + } + return undefined; + } + + async futuresTransfer (code: string, amount, type, params = {}) { + /** + * @method + * @name binance#futuresTransfer + * @ignore + * @description transfer between futures account + * @see https://binance-docs.github.io/apidocs/spot/en/#new-future-account-transfer-user_data + * @param {string} code unified currency code + * @param {float} amount the amount to transfer + * @param {string} type 1 - transfer from spot account to USDT-Ⓜ futures account, 2 - transfer from USDT-Ⓜ futures account to spot account, 3 - transfer from spot account to COIN-Ⓜ futures account, 4 - transfer from COIN-Ⓜ futures account to spot account + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {float} params.recvWindow + * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=futures-transfer-structure} + */ + if ((type < 1) || (type > 4)) { + throw new ArgumentsRequired (this.id + ' type must be between 1 and 4'); + } + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + 'amount': amount, + 'type': type, + }; + const response = await this.sapiPostFuturesTransfer (this.extend (request, params)); + // + // { + // "tranId": 100000001 + // } + // + return this.parseTransfer (response, currency); + } + + async fetchFundingRate (symbol: string, params = {}) { + /** + * @method + * @name binance#fetchFundingRate + * @description fetch the current funding rate + * @see https://binance-docs.github.io/apidocs/futures/en/#mark-price + * @see https://binance-docs.github.io/apidocs/delivery/en/#index-price-and-mark-price + * @param {string} symbol unified market symbol + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + let method = undefined; + if (market['linear']) { + method = 'fapiPublicGetPremiumIndex'; + } else if (market['inverse']) { + method = 'dapiPublicGetPremiumIndex'; + } else { + throw new NotSupported (this.id + ' fetchFundingRate() supports linear and inverse contracts only'); + } + let response = await this[method] (this.extend (request, params)); + if (market['inverse']) { + response = response[0]; + } + // + // { + // "symbol": "BTCUSDT", + // "markPrice": "45802.81129892", + // "indexPrice": "45745.47701915", + // "estimatedSettlePrice": "45133.91753671", + // "lastFundingRate": "0.00063521", + // "interestRate": "0.00010000", + // "nextFundingTime": "1621267200000", + // "time": "1621252344001" + // } + // + return this.parseFundingRate (response, market); + } + + async fetchFundingRateHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchFundingRateHistory + * @description fetches historical funding rate prices + * @see https://binance-docs.github.io/apidocs/futures/en/#get-funding-rate-history + * @see https://binance-docs.github.io/apidocs/delivery/en/#get-funding-rate-history-of-perpetual-futures + * @param {string} symbol unified symbol of the market to fetch the funding rate history for + * @param {int} [since] timestamp in ms of the earliest funding rate to fetch + * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {int} [params.until] timestamp in ms of the latest funding rate + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} + */ + await this.loadMarkets (); + const request = {}; + let method = undefined; + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchFundingRateHistory', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDeterministic ('fetchFundingRateHistory', symbol, since, limit, '8h', params) as FundingRateHistory[]; + } + const defaultType = this.safeString2 (this.options, 'fetchFundingRateHistory', 'defaultType', 'future'); + const type = this.safeString (params, 'type', defaultType); + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + symbol = market['symbol']; + request['symbol'] = market['id']; + } + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchFundingRateHistory', market, params, 'linear'); + params = this.omit (params, 'type'); + if (this.isLinear (type, subType)) { + method = 'fapiPublicGetFundingRate'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPublicGetFundingRate'; + } + if (method === undefined) { + throw new NotSupported (this.id + ' fetchFundingRateHistory() is not supported for ' + type + ' markets'); + } + if (since !== undefined) { + request['startTime'] = since; + } + const until = this.safeInteger2 (params, 'until', 'till'); // unified in milliseconds + const endTime = this.safeInteger (params, 'endTime', until); // exchange-specific in milliseconds + params = this.omit (params, [ 'endTime', 'till', 'until' ]); + if (endTime !== undefined) { + request['endTime'] = endTime; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "symbol": "BTCUSDT", + // "fundingRate": "0.00063521", + // "fundingTime": "1621267200000", + // } + // + const rates = []; + for (let i = 0; i < response.length; i++) { + const entry = response[i]; + const timestamp = this.safeInteger (entry, 'fundingTime'); + rates.push ({ + 'info': entry, + 'symbol': this.safeSymbol (this.safeString (entry, 'symbol'), undefined, undefined, 'swap'), + 'fundingRate': this.safeNumber (entry, 'fundingRate'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + }); + } + const sorted = this.sortBy (rates, 'timestamp'); + return this.filterBySymbolSinceLimit (sorted, symbol, since, limit) as FundingRateHistory[]; + } + + async fetchFundingRates (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchFundingRates + * @description fetch the funding rate for multiple markets + * @see https://binance-docs.github.io/apidocs/futures/en/#mark-price + * @see https://binance-docs.github.io/apidocs/delivery/en/#index-price-and-mark-price + * @param {string[]|undefined} symbols list of unified market symbols + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a dictionary of [funding rates structures]{@link https://docs.ccxt.com/#/?id=funding-rates-structure}, indexe by market symbols + */ + await this.loadMarkets (); + symbols = this.marketSymbols (symbols); + let method = undefined; + const defaultType = this.safeString2 (this.options, 'fetchFundingRates', 'defaultType', 'future'); + const type = this.safeString (params, 'type', defaultType); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchFundingRates', undefined, params, 'linear'); + const query = this.omit (params, 'type'); + if (this.isLinear (type, subType)) { + method = 'fapiPublicGetPremiumIndex'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPublicGetPremiumIndex'; + } else { + throw new NotSupported (this.id + ' fetchFundingRates() supports linear and inverse contracts only'); + } + const response = await this[method] (query); + const result = []; + for (let i = 0; i < response.length; i++) { + const entry = response[i]; + const parsed = this.parseFundingRate (entry); + result.push (parsed); + } + return this.filterByArray (result, 'symbol', symbols); + } + + parseFundingRate (contract, market: Market = undefined) { + // ensure it matches with https://www.binance.com/en/futures/funding-history/0 + // + // { + // "symbol": "BTCUSDT", + // "markPrice": "45802.81129892", + // "indexPrice": "45745.47701915", + // "estimatedSettlePrice": "45133.91753671", + // "lastFundingRate": "0.00063521", + // "interestRate": "0.00010000", + // "nextFundingTime": "1621267200000", + // "time": "1621252344001" + // } + // + const timestamp = this.safeInteger (contract, 'time'); + const marketId = this.safeString (contract, 'symbol'); + const symbol = this.safeSymbol (marketId, market, undefined, 'contract'); + const markPrice = this.safeNumber (contract, 'markPrice'); + const indexPrice = this.safeNumber (contract, 'indexPrice'); + const interestRate = this.safeNumber (contract, 'interestRate'); + const estimatedSettlePrice = this.safeNumber (contract, 'estimatedSettlePrice'); + const fundingRate = this.safeNumber (contract, 'lastFundingRate'); + const fundingTime = this.safeInteger (contract, 'nextFundingTime'); + return { + 'info': contract, + 'symbol': symbol, + 'markPrice': markPrice, + 'indexPrice': indexPrice, + 'interestRate': interestRate, + 'estimatedSettlePrice': estimatedSettlePrice, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'fundingRate': fundingRate, + 'fundingTimestamp': fundingTime, + 'fundingDatetime': this.iso8601 (fundingTime), + 'nextFundingRate': undefined, + 'nextFundingTimestamp': undefined, + 'nextFundingDatetime': undefined, + 'previousFundingRate': undefined, + 'previousFundingTimestamp': undefined, + 'previousFundingDatetime': undefined, + }; + } + + parseAccountPositions (account) { + const positions = this.safeValue (account, 'positions'); + const assets = this.safeValue (account, 'assets', []); + const balances = {}; + for (let i = 0; i < assets.length; i++) { + const entry = assets[i]; + const currencyId = this.safeString (entry, 'asset'); + const code = this.safeCurrencyCode (currencyId); + const crossWalletBalance = this.safeString (entry, 'crossWalletBalance'); + const crossUnPnl = this.safeString (entry, 'crossUnPnl'); + balances[code] = { + 'crossMargin': Precise.stringAdd (crossWalletBalance, crossUnPnl), + 'crossWalletBalance': crossWalletBalance, + }; + } + const result = []; + for (let i = 0; i < positions.length; i++) { + const position = positions[i]; + const marketId = this.safeString (position, 'symbol'); + const market = this.safeMarket (marketId, undefined, undefined, 'contract'); + const code = market['linear'] ? market['quote'] : market['base']; + // sometimes not all the codes are correctly returned... + if (code in balances) { + const parsed = this.parseAccountPosition (this.extend (position, { + 'crossMargin': balances[code]['crossMargin'], + 'crossWalletBalance': balances[code]['crossWalletBalance'], + }), market); + result.push (parsed); + } + } + return result; + } + + parseAccountPosition (position, market: Market = undefined) { + // + // usdm + // { + // "symbol": "BTCBUSD", + // "initialMargin": "0", + // "maintMargin": "0", + // "unrealizedProfit": "0.00000000", + // "positionInitialMargin": "0", + // "openOrderInitialMargin": "0", + // "leverage": "20", + // "isolated": false, + // "entryPrice": "0.0000", + // "maxNotional": "100000", + // "positionSide": "BOTH", + // "positionAmt": "0.000", + // "notional": "0", + // "isolatedWallet": "0", + // "updateTime": "0", + // "crossMargin": "100.93634809", + // } + // + // coinm + // { + // "symbol": "BTCUSD_210625", + // "initialMargin": "0.00024393", + // "maintMargin": "0.00002439", + // "unrealizedProfit": "-0.00000163", + // "positionInitialMargin": "0.00024393", + // "openOrderInitialMargin": "0", + // "leverage": "10", + // "isolated": false, + // "positionSide": "BOTH", + // "entryPrice": "41021.20000069", + // "maxQty": "100", + // "notionalValue": "0.00243939", + // "isolatedWallet": "0", + // "crossMargin": "0.314" + // "crossWalletBalance": "34", + // } + // + const marketId = this.safeString (position, 'symbol'); + market = this.safeMarket (marketId, market, undefined, 'contract'); + const symbol = this.safeString (market, 'symbol'); + const leverageString = this.safeString (position, 'leverage'); + const leverage = parseInt (leverageString); + const initialMarginString = this.safeString (position, 'initialMargin'); + const initialMargin = this.parseNumber (initialMarginString); + let initialMarginPercentageString = Precise.stringDiv ('1', leverageString, 8); + const rational = this.isRoundNumber (1000 % leverage); + if (!rational) { + initialMarginPercentageString = Precise.stringDiv (Precise.stringAdd (initialMarginPercentageString, '1e-8'), '1', 8); + } + // as oppose to notionalValue + const usdm = ('notional' in position); + const maintenanceMarginString = this.safeString (position, 'maintMargin'); + const maintenanceMargin = this.parseNumber (maintenanceMarginString); + const entryPriceString = this.safeString (position, 'entryPrice'); + let entryPrice = this.parseNumber (entryPriceString); + const notionalString = this.safeString2 (position, 'notional', 'notionalValue'); + const notionalStringAbs = Precise.stringAbs (notionalString); + const notional = this.parseNumber (notionalStringAbs); + let contractsString = this.safeString (position, 'positionAmt'); + let contractsStringAbs = Precise.stringAbs (contractsString); + if (contractsString === undefined) { + const entryNotional = Precise.stringMul (Precise.stringMul (leverageString, initialMarginString), entryPriceString); + const contractSizeNew = this.safeString (market, 'contractSize'); + contractsString = Precise.stringDiv (entryNotional, contractSizeNew); + contractsStringAbs = Precise.stringDiv (Precise.stringAdd (contractsString, '0.5'), '1', 0); + } + const contracts = this.parseNumber (contractsStringAbs); + const leverageBrackets = this.safeValue (this.options, 'leverageBrackets', {}); + const leverageBracket = this.safeValue (leverageBrackets, symbol, []); + let maintenanceMarginPercentageString = undefined; + for (let i = 0; i < leverageBracket.length; i++) { + const bracket = leverageBracket[i]; + if (Precise.stringLt (notionalStringAbs, bracket[0])) { + break; + } + maintenanceMarginPercentageString = bracket[1]; + } + const maintenanceMarginPercentage = this.parseNumber (maintenanceMarginPercentageString); + const unrealizedPnlString = this.safeString (position, 'unrealizedProfit'); + const unrealizedPnl = this.parseNumber (unrealizedPnlString); + let timestamp = this.safeInteger (position, 'updateTime'); + if (timestamp === 0) { + timestamp = undefined; + } + const isolated = this.safeValue (position, 'isolated'); + let marginMode = undefined; + let collateralString = undefined; + let walletBalance = undefined; + if (isolated) { + marginMode = 'isolated'; + walletBalance = this.safeString (position, 'isolatedWallet'); + collateralString = Precise.stringAdd (walletBalance, unrealizedPnlString); + } else { + marginMode = 'cross'; + walletBalance = this.safeString (position, 'crossWalletBalance'); + collateralString = this.safeString (position, 'crossMargin'); + } + const collateral = this.parseNumber (collateralString); + let marginRatio = undefined; + let side = undefined; + let percentage = undefined; + let liquidationPriceStringRaw = undefined; + let liquidationPrice = undefined; + const contractSize = this.safeValue (market, 'contractSize'); + const contractSizeString = this.numberToString (contractSize); + if (Precise.stringEquals (notionalString, '0')) { + entryPrice = undefined; + } else { + side = Precise.stringLt (notionalString, '0') ? 'short' : 'long'; + marginRatio = this.parseNumber (Precise.stringDiv (Precise.stringAdd (Precise.stringDiv (maintenanceMarginString, collateralString), '5e-5'), '1', 4)); + percentage = this.parseNumber (Precise.stringMul (Precise.stringDiv (unrealizedPnlString, initialMarginString, 4), '100')); + if (usdm) { + // calculate liquidation price + // + // liquidationPrice = (walletBalance / (contracts * (±1 + mmp))) + (±entryPrice / (±1 + mmp)) + // + // mmp = maintenanceMarginPercentage + // where ± is negative for long and positive for short + // TODO: calculate liquidation price for coinm contracts + let onePlusMaintenanceMarginPercentageString = undefined; + let entryPriceSignString = entryPriceString; + if (side === 'short') { + onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('1', maintenanceMarginPercentageString); + } else { + onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('-1', maintenanceMarginPercentageString); + entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); + } + const leftSide = Precise.stringDiv (walletBalance, Precise.stringMul (contractsStringAbs, onePlusMaintenanceMarginPercentageString)); + const rightSide = Precise.stringDiv (entryPriceSignString, onePlusMaintenanceMarginPercentageString); + liquidationPriceStringRaw = Precise.stringAdd (leftSide, rightSide); + } else { + // calculate liquidation price + // + // liquidationPrice = (contracts * contractSize(±1 - mmp)) / (±1/entryPrice * contracts * contractSize - walletBalance) + // + let onePlusMaintenanceMarginPercentageString = undefined; + let entryPriceSignString = entryPriceString; + if (side === 'short') { + onePlusMaintenanceMarginPercentageString = Precise.stringSub ('1', maintenanceMarginPercentageString); + } else { + onePlusMaintenanceMarginPercentageString = Precise.stringSub ('-1', maintenanceMarginPercentageString); + entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); + } + const size = Precise.stringMul (contractsStringAbs, contractSizeString); + const leftSide = Precise.stringMul (size, onePlusMaintenanceMarginPercentageString); + const rightSide = Precise.stringSub (Precise.stringMul (Precise.stringDiv ('1', entryPriceSignString), size), walletBalance); + liquidationPriceStringRaw = Precise.stringDiv (leftSide, rightSide); + } + const pricePrecision = market['precision']['price']; + const pricePrecisionPlusOne = pricePrecision + 1; + const pricePrecisionPlusOneString = pricePrecisionPlusOne.toString (); + // round half up + const rounder = new Precise ('5e-' + pricePrecisionPlusOneString); + const rounderString = rounder.toString (); + const liquidationPriceRoundedString = Precise.stringAdd (rounderString, liquidationPriceStringRaw); + let truncatedLiquidationPrice = Precise.stringDiv (liquidationPriceRoundedString, '1', pricePrecision); + if (truncatedLiquidationPrice[0] === '-') { + // user cannot be liquidated + // since he has more collateral than the size of the position + truncatedLiquidationPrice = undefined; + } + liquidationPrice = this.parseNumber (truncatedLiquidationPrice); + } + const positionSide = this.safeString (position, 'positionSide'); + const hedged = positionSide !== 'BOTH'; + return { + 'info': position, + 'id': undefined, + 'symbol': symbol, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'initialMargin': initialMargin, + 'initialMarginPercentage': this.parseNumber (initialMarginPercentageString), + 'maintenanceMargin': maintenanceMargin, + 'maintenanceMarginPercentage': maintenanceMarginPercentage, + 'entryPrice': entryPrice, + 'notional': notional, + 'leverage': this.parseNumber (leverageString), + 'unrealizedPnl': unrealizedPnl, + 'contracts': contracts, + 'contractSize': contractSize, + 'marginRatio': marginRatio, + 'liquidationPrice': liquidationPrice, + 'markPrice': undefined, + 'collateral': collateral, + 'marginMode': marginMode, + 'side': side, + 'hedged': hedged, + 'percentage': percentage, + }; + } + + parsePositionRisk (position, market: Market = undefined) { + // + // usdm + // + // { + // "symbol": "BTCUSDT", + // "positionAmt": "0.001", + // "entryPrice": "43578.07000", + // "markPrice": "43532.30000000", + // "unRealizedProfit": "-0.04577000", + // "liquidationPrice": "21841.24993976", + // "leverage": "2", + // "maxNotionalValue": "300000000", + // "marginType": "isolated", + // "isolatedMargin": "21.77841506", + // "isAutoAddMargin": "false", + // "positionSide": "BOTH", + // "notional": "43.53230000", + // "isolatedWallet": "21.82418506", + // "updateTime": "1621358023886" + // } + // + // coinm + // + // { + // "symbol": "BTCUSD_PERP", + // "positionAmt": "2", + // "entryPrice": "37643.10000021", + // "markPrice": "38103.05510455", + // "unRealizedProfit": "0.00006413", + // "liquidationPrice": "25119.97445760", + // "leverage": "2", + // "maxQty": "1500", + // "marginType": "isolated", + // "isolatedMargin": "0.00274471", + // "isAutoAddMargin": "false", + // "positionSide": "BOTH", + // "notionalValue": "0.00524892", + // "isolatedWallet": "0.00268058" + // } + // + const marketId = this.safeString (position, 'symbol'); + market = this.safeMarket (marketId, market, undefined, 'contract'); + const symbol = this.safeString (market, 'symbol'); + const leverageBrackets = this.safeValue (this.options, 'leverageBrackets', {}); + const leverageBracket = this.safeValue (leverageBrackets, symbol, []); + const notionalString = this.safeString2 (position, 'notional', 'notionalValue'); + const notionalStringAbs = Precise.stringAbs (notionalString); + let maintenanceMarginPercentageString = undefined; + for (let i = 0; i < leverageBracket.length; i++) { + const bracket = leverageBracket[i]; + if (Precise.stringLt (notionalStringAbs, bracket[0])) { + break; + } + maintenanceMarginPercentageString = bracket[1]; + } + const notional = this.parseNumber (notionalStringAbs); + const contractsAbs = Precise.stringAbs (this.safeString (position, 'positionAmt')); + const contracts = this.parseNumber (contractsAbs); + const unrealizedPnlString = this.safeString (position, 'unRealizedProfit'); + const unrealizedPnl = this.parseNumber (unrealizedPnlString); + const leverageString = this.safeString (position, 'leverage'); + const leverage = parseInt (leverageString); + const liquidationPriceString = this.omitZero (this.safeString (position, 'liquidationPrice')); + const liquidationPrice = this.parseNumber (liquidationPriceString); + let collateralString = undefined; + const marginMode = this.safeString (position, 'marginType'); + let side = undefined; + if (Precise.stringGt (notionalString, '0')) { + side = 'long'; + } else if (Precise.stringLt (notionalString, '0')) { + side = 'short'; + } + const entryPriceString = this.safeString (position, 'entryPrice'); + const entryPrice = this.parseNumber (entryPriceString); + const contractSize = this.safeValue (market, 'contractSize'); + const contractSizeString = this.numberToString (contractSize); + // as oppose to notionalValue + const linear = ('notional' in position); + if (marginMode === 'cross') { + // calculate collateral + const precision = this.safeValue (market, 'precision', {}); + if (linear) { + // walletBalance = (liquidationPrice * (±1 + mmp) ± entryPrice) * contracts + let onePlusMaintenanceMarginPercentageString = undefined; + let entryPriceSignString = entryPriceString; + if (side === 'short') { + onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('1', maintenanceMarginPercentageString); + entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); + } else { + onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('-1', maintenanceMarginPercentageString); + } + const inner = Precise.stringMul (liquidationPriceString, onePlusMaintenanceMarginPercentageString); + const leftSide = Precise.stringAdd (inner, entryPriceSignString); + const pricePrecision = this.safeInteger (precision, 'price'); + const quotePrecision = this.safeInteger (precision, 'quote', pricePrecision); + if (quotePrecision !== undefined) { + collateralString = Precise.stringDiv (Precise.stringMul (leftSide, contractsAbs), '1', quotePrecision); + } + } else { + // walletBalance = (contracts * contractSize) * (±1/entryPrice - (±1 - mmp) / liquidationPrice) + let onePlusMaintenanceMarginPercentageString = undefined; + let entryPriceSignString = entryPriceString; + if (side === 'short') { + onePlusMaintenanceMarginPercentageString = Precise.stringSub ('1', maintenanceMarginPercentageString); + } else { + onePlusMaintenanceMarginPercentageString = Precise.stringSub ('-1', maintenanceMarginPercentageString); + entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); + } + const leftSide = Precise.stringMul (contractsAbs, contractSizeString); + const rightSide = Precise.stringSub (Precise.stringDiv ('1', entryPriceSignString), Precise.stringDiv (onePlusMaintenanceMarginPercentageString, liquidationPriceString)); + const basePrecision = this.safeInteger (precision, 'base'); + if (basePrecision !== undefined) { + collateralString = Precise.stringDiv (Precise.stringMul (leftSide, rightSide), '1', basePrecision); + } + } + } else { + collateralString = this.safeString (position, 'isolatedMargin'); + } + collateralString = (collateralString === undefined) ? '0' : collateralString; + const collateral = this.parseNumber (collateralString); + const markPrice = this.parseNumber (this.omitZero (this.safeString (position, 'markPrice'))); + let timestamp = this.safeInteger (position, 'updateTime'); + if (timestamp === 0) { + timestamp = undefined; + } + const maintenanceMarginPercentage = this.parseNumber (maintenanceMarginPercentageString); + const maintenanceMarginString = Precise.stringMul (maintenanceMarginPercentageString, notionalStringAbs); + const maintenanceMargin = this.parseNumber (maintenanceMarginString); + let initialMarginPercentageString = Precise.stringDiv ('1', leverageString, 8); + const rational = this.isRoundNumber (1000 % leverage); + if (!rational) { + initialMarginPercentageString = Precise.stringAdd (initialMarginPercentageString, '1e-8'); + } + const initialMarginString = Precise.stringDiv (Precise.stringMul (notionalStringAbs, initialMarginPercentageString), '1', 8); + const initialMargin = this.parseNumber (initialMarginString); + let marginRatio = undefined; + let percentage = undefined; + if (!Precise.stringEquals (collateralString, '0')) { + marginRatio = this.parseNumber (Precise.stringDiv (Precise.stringAdd (Precise.stringDiv (maintenanceMarginString, collateralString), '5e-5'), '1', 4)); + percentage = this.parseNumber (Precise.stringMul (Precise.stringDiv (unrealizedPnlString, initialMarginString, 4), '100')); + } + const positionSide = this.safeString (position, 'positionSide'); + const hedged = positionSide !== 'BOTH'; + return { + 'info': position, + 'id': undefined, + 'symbol': symbol, + 'contracts': contracts, + 'contractSize': contractSize, + 'unrealizedPnl': unrealizedPnl, + 'leverage': this.parseNumber (leverageString), + 'liquidationPrice': liquidationPrice, + 'collateral': collateral, + 'notional': notional, + 'markPrice': markPrice, + 'entryPrice': entryPrice, + 'timestamp': timestamp, + 'initialMargin': initialMargin, + 'initialMarginPercentage': this.parseNumber (initialMarginPercentageString), + 'maintenanceMargin': maintenanceMargin, + 'maintenanceMarginPercentage': maintenanceMarginPercentage, + 'marginRatio': marginRatio, + 'datetime': this.iso8601 (timestamp), + 'marginMode': marginMode, + 'marginType': marginMode, // deprecated + 'side': side, + 'hedged': hedged, + 'percentage': percentage, + 'stopLossPrice': undefined, + 'takeProfitPrice': undefined, + }; + } + + async loadLeverageBrackets (reload = false, params = {}) { + await this.loadMarkets (); + // by default cache the leverage bracket + // it contains useful stuff like the maintenance margin and initial margin for positions + const leverageBrackets = this.safeValue (this.options, 'leverageBrackets'); + if ((leverageBrackets === undefined) || (reload)) { + let method = undefined; + const defaultType = this.safeString (this.options, 'defaultType', 'future'); + const type = this.safeString (params, 'type', defaultType); + const query = this.omit (params, 'type'); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('loadLeverageBrackets', undefined, params, 'linear'); + if (this.isLinear (type, subType)) { + method = 'fapiPrivateGetLeverageBracket'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateV2GetLeverageBracket'; + } else { + throw new NotSupported (this.id + ' loadLeverageBrackets() supports linear and inverse contracts only'); + } + const response = await this[method] (query); + this.options['leverageBrackets'] = {}; + for (let i = 0; i < response.length; i++) { + const entry = response[i]; + const marketId = this.safeString (entry, 'symbol'); + const symbol = this.safeSymbol (marketId, undefined, undefined, 'contract'); + const brackets = this.safeValue (entry, 'brackets', []); + const result = []; + for (let j = 0; j < brackets.length; j++) { + const bracket = brackets[j]; + const floorValue = this.safeString2 (bracket, 'notionalFloor', 'qtyFloor'); + const maintenanceMarginPercentage = this.safeString (bracket, 'maintMarginRatio'); + result.push ([ floorValue, maintenanceMarginPercentage ]); + } + this.options['leverageBrackets'][symbol] = result; + } + } + return this.options['leverageBrackets']; + } + + async fetchLeverageTiers (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchLeverageTiers + * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes + * @see https://binance-docs.github.io/apidocs/futures/en/#notional-and-leverage-brackets-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#notional-bracket-for-symbol-user_data + * @param {string[]|undefined} symbols list of unified market symbols + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}, indexed by market symbols + */ + await this.loadMarkets (); + const [ type, query ] = this.handleMarketTypeAndParams ('fetchLeverageTiers', undefined, params); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchLeverageTiers', undefined, query, 'linear'); + let method = undefined; + if (this.isLinear (type, subType)) { + method = 'fapiPrivateGetLeverageBracket'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateV2GetLeverageBracket'; + } else { + throw new NotSupported (this.id + ' fetchLeverageTiers() supports linear and inverse contracts only'); + } + const response = await this[method] (query); + // + // usdm + // + // [ + // { + // "symbol": "SUSHIUSDT", + // "brackets": [ + // { + // "bracket": 1, + // "initialLeverage": 50, + // "notionalCap": 50000, + // "notionalFloor": 0, + // "maintMarginRatio": 0.01, + // "cum": 0.0 + // }, + // ... + // ] + // } + // ] + // + // coinm + // + // [ + // { + // "symbol":"XRPUSD_210326", + // "brackets":[ + // { + // "bracket":1, + // "initialLeverage":20, + // "qtyCap":500000, + // "qtyFloor":0, + // "maintMarginRatio":0.0185, + // "cum":0.0 + // } + // ] + // } + // ] + // + return this.parseLeverageTiers (response, symbols, 'symbol'); + } + + parseMarketLeverageTiers (info, market: Market = undefined) { + /** + * @ignore + * @method + * @param {object} info Exchange response for 1 market + * @param {object} market CCXT market + */ + // + // { + // "symbol": "SUSHIUSDT", + // "brackets": [ + // { + // "bracket": 1, + // "initialLeverage": 50, + // "notionalCap": 50000, + // "notionalFloor": 0, + // "maintMarginRatio": 0.01, + // "cum": 0.0 + // }, + // ... + // ] + // } + // + const marketId = this.safeString (info, 'symbol'); + market = this.safeMarket (marketId, market, undefined, 'contract'); + const brackets = this.safeValue (info, 'brackets', []); + const tiers = []; + for (let j = 0; j < brackets.length; j++) { + const bracket = brackets[j]; + tiers.push ({ + 'tier': this.safeNumber (bracket, 'bracket'), + 'currency': market['quote'], + 'minNotional': this.safeNumber2 (bracket, 'notionalFloor', 'qtyFloor'), + 'maxNotional': this.safeNumber2 (bracket, 'notionalCap', 'qtyCap'), + 'maintenanceMarginRate': this.safeNumber (bracket, 'maintMarginRatio'), + 'maxLeverage': this.safeNumber (bracket, 'initialLeverage'), + 'info': bracket, + }); + } + return tiers; + } + + async fetchPosition (symbol: string, params = {}) { + /** + * @method + * @name binance#fetchPosition + * @see https://binance-docs.github.io/apidocs/voptions/en/#option-position-information-user_data + * @description fetch data on an open position + * @param {string} symbol unified market symbol of the market the position is held in + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + if (!market['option']) { + throw new NotSupported (this.id + ' fetchPosition() supports option markets only'); + } + const request = { + 'symbol': market['id'], + }; + const response = await this.eapiPrivateGetPosition (this.extend (request, params)); + // + // [ + // { + // "entryPrice": "27.70000000", + // "symbol": "ETH-230426-1850-C", + // "side": "LONG", + // "quantity": "0.50000000", + // "reducibleQty": "0.50000000", + // "markValue": "10.250000000", + // "ror": "-0.2599", + // "unrealizedPNL": "-3.600000000", + // "markPrice": "20.5", + // "strikePrice": "1850.00000000", + // "positionCost": "13.85000000", + // "expiryDate": 1682496000000, + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT", + // "time": 1682492427106 + // } + // ] + // + return this.parsePosition (response[0], market); + } + + async fetchOptionPositions (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchOptionPositions + * @see https://binance-docs.github.io/apidocs/voptions/en/#option-position-information-user_data + * @description fetch data on open options positions + * @param {string[]|undefined} symbols list of unified market symbols + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure} + */ + await this.loadMarkets (); + symbols = this.marketSymbols (symbols); + const request = {}; + let market = undefined; + if (symbols !== undefined) { + let symbol = undefined; + if (Array.isArray (symbols)) { + const symbolsLength = symbols.length; + if (symbolsLength > 1) { + throw new BadRequest (this.id + ' fetchPositions() symbols argument cannot contain more than 1 symbol'); + } + symbol = symbols[0]; + } else { + symbol = symbols; + } + market = this.market (symbol); + request['symbol'] = market['id']; + } + const response = await this.eapiPrivateGetPosition (this.extend (request, params)); + // + // [ + // { + // "entryPrice": "27.70000000", + // "symbol": "ETH-230426-1850-C", + // "side": "LONG", + // "quantity": "0.50000000", + // "reducibleQty": "0.50000000", + // "markValue": "10.250000000", + // "ror": "-0.2599", + // "unrealizedPNL": "-3.600000000", + // "markPrice": "20.5", + // "strikePrice": "1850.00000000", + // "positionCost": "13.85000000", + // "expiryDate": 1682496000000, + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT", + // "time": 1682492427106 + // } + // ] + // + const result = []; + for (let i = 0; i < response.length; i++) { + result.push (this.parsePosition (response[i], market)); + } + return this.filterByArrayPositions (result, 'symbol', symbols, false); + } + + parsePosition (position, market: Market = undefined) { + // + // { + // "entryPrice": "27.70000000", + // "symbol": "ETH-230426-1850-C", + // "side": "LONG", + // "quantity": "0.50000000", + // "reducibleQty": "0.50000000", + // "markValue": "10.250000000", + // "ror": "-0.2599", + // "unrealizedPNL": "-3.600000000", + // "markPrice": "20.5", + // "strikePrice": "1850.00000000", + // "positionCost": "13.85000000", + // "expiryDate": 1682496000000, + // "priceScale": 1, + // "quantityScale": 2, + // "optionSide": "CALL", + // "quoteAsset": "USDT", + // "time": 1682492427106 + // } + // + const marketId = this.safeString (position, 'symbol'); + market = this.safeMarket (marketId, market); + const symbol = market['symbol']; + const side = this.safeStringLower (position, 'side'); + let quantity = this.safeString (position, 'quantity'); + if (side !== 'long') { + quantity = Precise.stringMul ('-1', quantity); + } + const timestamp = this.safeInteger (position, 'time'); + return this.safePosition ({ + 'info': position, + 'id': undefined, + 'symbol': symbol, + 'entryPrice': this.safeNumber (position, 'entryPrice'), + 'markPrice': this.safeNumber (position, 'markPrice'), + 'notional': this.safeNumber (position, 'markValue'), + 'collateral': this.safeNumber (position, 'positionCost'), + 'unrealizedPnl': this.safeNumber (position, 'unrealizedPNL'), + 'side': side, + 'contracts': this.parseNumber (quantity), + 'contractSize': undefined, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'hedged': undefined, + 'maintenanceMargin': undefined, + 'maintenanceMarginPercentage': undefined, + 'initialMargin': undefined, + 'initialMarginPercentage': undefined, + 'leverage': undefined, + 'liquidationPrice': undefined, + 'marginRatio': undefined, + 'marginMode': undefined, + 'percentage': undefined, + }); + } + + async fetchPositions (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchPositions + * @description fetch all open positions + * @param {string[]|undefined} symbols list of unified market symbols + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} + */ + const defaultMethod = this.safeString (this.options, 'fetchPositions', 'positionRisk'); + if (defaultMethod === 'positionRisk') { + return await this.fetchPositionsRisk (symbols, params); + } else if (defaultMethod === 'account') { + return await this.fetchAccountPositions (symbols, params); + } else if (defaultMethod === 'option') { + return await this.fetchOptionPositions (symbols, params); + } else { + throw new NotSupported (this.id + '.options["fetchPositions"] = "' + defaultMethod + '" is invalid, please choose between "account", "positionRisk" and "option"'); + } + } + + async fetchAccountPositions (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchAccountPositions + * @ignore + * @description fetch account positions + * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data + * @param {string[]|undefined} symbols list of unified market symbols + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} data on account positions + */ + if (symbols !== undefined) { + if (!Array.isArray (symbols)) { + throw new ArgumentsRequired (this.id + ' fetchPositions() requires an array argument for symbols'); + } + } + await this.loadMarkets (); + await this.loadLeverageBrackets (false, params); + let method = undefined; + const defaultType = this.safeString (this.options, 'defaultType', 'future'); + const type = this.safeString (params, 'type', defaultType); + let query = this.omit (params, 'type'); + let subType = undefined; + [ subType, query ] = this.handleSubTypeAndParams ('fetchAccountPositions', undefined, params, 'linear'); + if (this.isLinear (type, subType)) { + method = 'fapiPrivateV2GetAccount'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateGetAccount'; + } else { + throw new NotSupported (this.id + ' fetchPositions() supports linear and inverse contracts only'); + } + const account = await this[method] (query); + const result = this.parseAccountPositions (account); + symbols = this.marketSymbols (symbols); + return this.filterByArrayPositions (result, 'symbol', symbols, false); + } + + async fetchPositionsRisk (symbols: Strings = undefined, params = {}) { + /** + * @method + * @name binance#fetchPositionsRisk + * @ignore + * @description fetch positions risk + * @see https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#position-information-user_data + * @param {string[]|undefined} symbols list of unified market symbols + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} data on the positions risk + */ + if (symbols !== undefined) { + if (!Array.isArray (symbols)) { + throw new ArgumentsRequired (this.id + ' fetchPositionsRisk() requires an array argument for symbols'); + } + } + await this.loadMarkets (); + await this.loadLeverageBrackets (false, params); + const request = {}; + let method = undefined; + let defaultType = 'future'; + defaultType = this.safeString (this.options, 'defaultType', defaultType); + const type = this.safeString (params, 'type', defaultType); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchPositionsRisk', undefined, params, 'linear'); + params = this.omit (params, 'type'); + if (this.isLinear (type, subType)) { + method = 'fapiPrivateV2GetPositionRisk'; + // ### Response examples ### + // + // For One-way position mode: + // [ + // { + // "entryPrice": "0.00000", + // "marginType": "isolated", + // "isAutoAddMargin": "false", + // "isolatedMargin": "0.00000000", + // "leverage": "10", + // "liquidationPrice": "0", + // "markPrice": "6679.50671178", + // "maxNotionalValue": "20000000", + // "positionAmt": "0.000", + // "symbol": "BTCUSDT", + // "unRealizedProfit": "0.00000000", + // "positionSide": "BOTH", + // "updateTime": 0 + // } + // ] + // + // For Hedge position mode: + // [ + // { + // "entryPrice": "6563.66500", + // "marginType": "isolated", + // "isAutoAddMargin": "false", + // "isolatedMargin": "15517.54150468", + // "leverage": "10", + // "liquidationPrice": "5930.78", + // "markPrice": "6679.50671178", + // "maxNotionalValue": "20000000", + // "positionAmt": "20.000", + // "symbol": "BTCUSDT", + // "unRealizedProfit": "2316.83423560" + // "positionSide": "LONG", + // "updateTime": 1625474304765 + // }, + // { + // "entryPrice": "0.00000", + // "marginType": "isolated", + // "isAutoAddMargin": "false", + // "isolatedMargin": "5413.95799991", + // "leverage": "10", + // "liquidationPrice": "7189.95", + // "markPrice": "6679.50671178", + // "maxNotionalValue": "20000000", + // "positionAmt": "-10.000", + // "symbol": "BTCUSDT", + // "unRealizedProfit": "-1156.46711780", + // "positionSide": "SHORT", + // "updateTime": 0 + // } + // ] + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateGetPositionRisk'; + } else { + throw new NotSupported (this.id + ' fetchPositionsRisk() supports linear and inverse contracts only'); + } + const response = await this[method] (this.extend (request, params)); + const result = []; + for (let i = 0; i < response.length; i++) { + const parsed = this.parsePositionRisk (response[i]); + result.push (parsed); + } + symbols = this.marketSymbols (symbols); + return this.filterByArrayPositions (result, 'symbol', symbols, false); + } + + async fetchFundingHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchFundingHistory + * @description fetch the history of funding payments paid and received on this account + * @see https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data + * @param {string} symbol unified market symbol + * @param {int} [since] the earliest time in ms to fetch funding history for + * @param {int} [limit] the maximum number of funding history structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure} + */ + await this.loadMarkets (); + let market = undefined; + let method = undefined; + const request = { + 'incomeType': 'FUNDING_FEE', // "TRANSFER","WELCOME_BONUS", "REALIZED_PNL","FUNDING_FEE", "COMMISSION" and "INSURANCE_CLEAR" + }; + if (symbol !== undefined) { + market = this.market (symbol); + request['symbol'] = market['id']; + if (!market['swap']) { + throw new NotSupported (this.id + ' fetchFundingHistory() supports swap contracts only'); + } + } + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchFundingHistory', market, params, 'linear'); + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const defaultType = this.safeString2 (this.options, 'fetchFundingHistory', 'defaultType', 'future'); + const type = this.safeString (params, 'type', defaultType); + params = this.omit (params, 'type'); + if (this.isLinear (type, subType)) { + method = 'fapiPrivateGetIncome'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateGetIncome'; + } else { + throw new NotSupported (this.id + ' fetchFundingHistory() supports linear and inverse contracts only'); + } + const response = await this[method] (this.extend (request, params)); + return this.parseIncomes (response, market, since, limit); + } + + async setLeverage (leverage, symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#setLeverage + * @description set the level of leverage for a market + * @see https://binance-docs.github.io/apidocs/futures/en/#change-initial-leverage-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#change-initial-leverage-trade + * @param {float} leverage the rate of leverage + * @param {string} symbol unified market symbol + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} response from the exchange + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' setLeverage() requires a symbol argument'); + } + // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS + // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS + if ((leverage < 1) || (leverage > 125)) { + throw new BadRequest (this.id + ' leverage should be between 1 and 125'); + } + await this.loadMarkets (); + const market = this.market (symbol); + let method: string; + if (market['linear']) { + method = 'fapiPrivatePostLeverage'; + } else if (market['inverse']) { + method = 'dapiPrivatePostLeverage'; + } else { + throw new NotSupported (this.id + ' setLeverage() supports linear and inverse contracts only'); + } + const request = { + 'symbol': market['id'], + 'leverage': leverage, + }; + return await this[method] (this.extend (request, params)); + } + + async setMarginMode (marginMode: string, symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#setMarginMode + * @description set margin mode to 'cross' or 'isolated' + * @see https://binance-docs.github.io/apidocs/futures/en/#change-margin-type-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#change-margin-type-trade + * @param {string} marginMode 'cross' or 'isolated' + * @param {string} symbol unified market symbol + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} response from the exchange + */ + if (symbol === undefined) { + throw new ArgumentsRequired (this.id + ' setMarginMode() requires a symbol argument'); + } + // + // { "code": -4048 , "msg": "Margin type cannot be changed if there exists position." } + // + // or + // + // { "code": 200, "msg": "success" } + // + marginMode = marginMode.toUpperCase (); + if (marginMode === 'CROSS') { + marginMode = 'CROSSED'; + } + if ((marginMode !== 'ISOLATED') && (marginMode !== 'CROSSED')) { + throw new BadRequest (this.id + ' marginMode must be either isolated or cross'); + } + await this.loadMarkets (); + const market = this.market (symbol); + let method = undefined; + if (market['linear']) { + method = 'fapiPrivatePostMarginType'; + } else if (market['inverse']) { + method = 'dapiPrivatePostMarginType'; + } else { + throw new NotSupported (this.id + ' setMarginMode() supports linear and inverse contracts only'); + } + const request = { + 'symbol': market['id'], + 'marginType': marginMode, + }; + let response = undefined; + try { + response = await this[method] (this.extend (request, params)); + } catch (e) { + // not an error + // https://github.com/ccxt/ccxt/issues/11268 + // https://github.com/ccxt/ccxt/pull/11624 + // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request + // binanceusdm + if (e instanceof MarginModeAlreadySet) { + const throwMarginModeAlreadySet = this.safeValue (this.options, 'throwMarginModeAlreadySet', false); + if (throwMarginModeAlreadySet) { + throw e; + } else { + response = { 'code': -4046, 'msg': 'No need to change margin type.' }; + } + } else { + throw e; + } + } + return response; + } + + async setPositionMode (hedged, symbol: Str = undefined, params = {}) { + /** + * @method + * @name binance#setPositionMode + * @description set hedged to true or false for a market + * @see https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade + * @see https://binance-docs.github.io/apidocs/delivery/en/#change-position-mode-trade + * @param {bool} hedged set to true to use dualSidePosition + * @param {string} symbol not used by binance setPositionMode () + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} response from the exchange + */ + const defaultType = this.safeString (this.options, 'defaultType', 'future'); + const type = this.safeString (params, 'type', defaultType); + params = this.omit (params, [ 'type' ]); + let dualSidePosition = undefined; + if (hedged) { + dualSidePosition = 'true'; + } else { + dualSidePosition = 'false'; + } + const request = { + 'dualSidePosition': dualSidePosition, + }; + let method = undefined; + if (this.isInverse (type)) { + method = 'dapiPrivatePostPositionSideDual'; + } else { + // default to future + method = 'fapiPrivatePostPositionSideDual'; + } + // + // { + // "code": 200, + // "msg": "success" + // } + // + return await this[method] (this.extend (request, params)); + } + + async fetchSettlementHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchSettlementHistory + * @description fetches historical settlement records + * @see https://binance-docs.github.io/apidocs/voptions/en/#historical-exercise-records + * @param {string} symbol unified market symbol of the settlement history + * @param {int} [since] timestamp in ms + * @param {int} [limit] number of records, default 100, max 100 + * @param {object} [params] exchange specific params + * @returns {object[]} a list of [settlement history objects]{@link https://docs.ccxt.com/#/?id=settlement-history-structure} + */ + await this.loadMarkets (); + const market = (symbol === undefined) ? undefined : this.market (symbol); + let type = undefined; + [ type, params ] = this.handleMarketTypeAndParams ('fetchSettlementHistory', market, params); + if (type !== 'option') { + throw new NotSupported (this.id + ' fetchSettlementHistory() supports option markets only'); + } + const request = {}; + if (symbol !== undefined) { + symbol = market['symbol']; + request['underlying'] = market['baseId'] + market['quoteId']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.eapiPublicGetExerciseHistory (this.extend (request, params)); + // + // [ + // { + // "symbol": "ETH-230223-1900-P", + // "strikePrice": "1900", + // "realStrikePrice": "1665.5897334", + // "expiryDate": 1677139200000, + // "strikeResult": "REALISTIC_VALUE_STRICKEN" + // } + // ] + // + const settlements = this.parseSettlements (response, market); + const sorted = this.sortBy (settlements, 'timestamp'); + return this.filterBySymbolSinceLimit (sorted, symbol, since, limit); + } + + async fetchMySettlementHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchMySettlementHistory + * @description fetches historical settlement records of the user + * @see https://binance-docs.github.io/apidocs/voptions/en/#user-exercise-record-user_data + * @param {string} symbol unified market symbol of the settlement history + * @param {int} [since] timestamp in ms + * @param {int} [limit] number of records + * @param {object} [params] exchange specific params + * @returns {object[]} a list of [settlement history objects] + */ + await this.loadMarkets (); + const market = (symbol === undefined) ? undefined : this.market (symbol); + let type = undefined; + [ type, params ] = this.handleMarketTypeAndParams ('fetchMySettlementHistory', market, params); + if (type !== 'option') { + throw new NotSupported (this.id + ' fetchMySettlementHistory() supports option markets only'); + } + const request = {}; + if (symbol !== undefined) { + request['symbol'] = market['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const response = await this.eapiPrivateGetExerciseRecord (this.extend (request, params)); + // + // [ + // { + // "id": "1125899906842897036", + // "currency": "USDT", + // "symbol": "BTC-230728-30000-C", + // "exercisePrice": "30000.00000000", + // "markPrice": "29160.71284993", + // "quantity": "1.00000000", + // "amount": "0.00000000", + // "fee": "0.00000000", + // "createDate": 1690531200000, + // "priceScale": 0, + // "quantityScale": 2, + // "optionSide": "CALL", + // "positionSide": "LONG", + // "quoteAsset": "USDT" + // } + // ] + // + const settlements = this.parseSettlements (response, market); + const sorted = this.sortBy (settlements, 'timestamp'); + return this.filterBySymbolSinceLimit (sorted, market['symbol'], since, limit); + } + + parseSettlement (settlement, market) { + // + // fetchSettlementHistory + // + // { + // "symbol": "ETH-230223-1900-P", + // "strikePrice": "1900", + // "realStrikePrice": "1665.5897334", + // "expiryDate": 1677139200000, + // "strikeResult": "REALISTIC_VALUE_STRICKEN" + // } + // + // fetchMySettlementHistory + // + // { + // "id": "1125899906842897036", + // "currency": "USDT", + // "symbol": "BTC-230728-30000-C", + // "exercisePrice": "30000.00000000", + // "markPrice": "29160.71284993", + // "quantity": "1.00000000", + // "amount": "0.00000000", + // "fee": "0.00000000", + // "createDate": 1690531200000, + // "priceScale": 0, + // "quantityScale": 2, + // "optionSide": "CALL", + // "positionSide": "LONG", + // "quoteAsset": "USDT" + // } + // + const timestamp = this.safeInteger2 (settlement, 'expiryDate', 'createDate'); + const marketId = this.safeString (settlement, 'symbol'); + return { + 'info': settlement, + 'symbol': this.safeSymbol (marketId, market), + 'price': this.safeNumber2 (settlement, 'realStrikePrice', 'exercisePrice'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + }; + } + + parseSettlements (settlements, market) { + // + // fetchSettlementHistory + // + // [ + // { + // "symbol": "ETH-230223-1900-P", + // "strikePrice": "1900", + // "realStrikePrice": "1665.5897334", + // "expiryDate": 1677139200000, + // "strikeResult": "EXTRINSIC_VALUE_EXPIRED" + // } + // ] + // + // fetchMySettlementHistory + // + // [ + // { + // "id": "1125899906842897036", + // "currency": "USDT", + // "symbol": "BTC-230728-30000-C", + // "exercisePrice": "30000.00000000", + // "markPrice": "29160.71284993", + // "quantity": "1.00000000", + // "amount": "0.00000000", + // "fee": "0.00000000", + // "createDate": 1690531200000, + // "priceScale": 0, + // "quantityScale": 2, + // "optionSide": "CALL", + // "positionSide": "LONG", + // "quoteAsset": "USDT" + // } + // ] + // + const result = []; + for (let i = 0; i < settlements.length; i++) { + result.push (this.parseSettlement (settlements[i], market)); + } + return result; + } + + async fetchLedger (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchLedger + * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user + * @see https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data + * @param {string} code unified currency code + * @param {int} [since] timestamp in ms of the earliest ledger entry + * @param {int} [limit] max number of ledger entrys to return + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @param {int} [params.until] timestamp in ms of the latest ledger entry + * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger-structure} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchLedger', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallDynamic ('fetchLedger', code, since, limit, params); + } + let type = undefined; + let subType = undefined; + let currency = undefined; + if (code !== undefined) { + currency = this.currency (code); + } + let method = undefined; + const request = {}; + [ type, params ] = this.handleMarketTypeAndParams ('fetchLedger', undefined, params); + [ subType, params ] = this.handleSubTypeAndParams ('fetchLedger', undefined, params); + if (type === 'option') { + this.checkRequiredArgument ('fetchLedger', code, 'code'); + request['currency'] = currency['id']; + method = 'eapiPrivateGetBill'; + } else if (this.isLinear (type, subType)) { + method = 'fapiPrivateGetIncome'; + } else if (this.isInverse (type, subType)) { + method = 'dapiPrivateGetIncome'; + } else { + throw new NotSupported (this.id + ' fetchLedger() supports contract wallets only'); + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['limit'] = limit; + } + const until = this.safeInteger (params, 'until'); + if (until !== undefined) { + params = this.omit (params, 'until'); + request['endTime'] = until; + } + const response = await this[method] (this.extend (request, params)); + // + // options (eapi) + // + // [ + // { + // "id": "1125899906845701870", + // "asset": "USDT", + // "amount": "-0.16518203", + // "type": "FEE", + // "createDate": 1676621042489 + // } + // ] + // + // futures (fapi, dapi) + // + // [ + // { + // "symbol": "", + // "incomeType": "TRANSFER", + // "income": "10.00000000", + // "asset": "USDT", + // "time": 1677645250000, + // "info": "TRANSFER", + // "tranId": 131001573082, + // "tradeId": "" + // } + // ] + // + return this.parseLedger (response, currency, since, limit); + } + + parseLedgerEntry (item, currency: Currency = undefined) { + // + // options (eapi) + // + // { + // "id": "1125899906845701870", + // "asset": "USDT", + // "amount": "-0.16518203", + // "type": "FEE", + // "createDate": 1676621042489 + // } + // + // futures (fapi, dapi) + // + // { + // "symbol": "", + // "incomeType": "TRANSFER", + // "income": "10.00000000", + // "asset": "USDT", + // "time": 1677645250000, + // "info": "TRANSFER", + // "tranId": 131001573082, + // "tradeId": "" + // } + // + let amount = this.safeString2 (item, 'amount', 'income'); + let direction = undefined; + if (Precise.stringLe (amount, '0')) { + direction = 'out'; + amount = Precise.stringMul ('-1', amount); + } else { + direction = 'in'; + } + const currencyId = this.safeString (item, 'asset'); + const timestamp = this.safeInteger2 (item, 'createDate', 'time'); + const type = this.safeString2 (item, 'type', 'incomeType'); + return { + 'id': this.safeString2 (item, 'id', 'tranId'), + 'direction': direction, + 'account': undefined, + 'referenceAccount': undefined, + 'referenceId': this.safeString (item, 'tradeId'), + 'type': this.parseLedgerEntryType (type), + 'currency': this.safeCurrencyCode (currencyId, currency), + 'amount': this.parseNumber (amount), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'before': undefined, + 'after': undefined, + 'status': undefined, + 'fee': undefined, + 'info': item, + }; + } + + parseLedgerEntryType (type) { + const ledgerType = { + 'FEE': 'fee', + 'FUNDING_FEE': 'fee', + 'OPTIONS_PREMIUM_FEE': 'fee', + 'POSITION_LIMIT_INCREASE_FEE': 'fee', + 'CONTRACT': 'trade', + 'REALIZED_PNL': 'trade', + 'TRANSFER': 'transfer', + 'CROSS_COLLATERAL_TRANSFER': 'transfer', + 'INTERNAL_TRANSFER': 'transfer', + 'COIN_SWAP_DEPOSIT': 'deposit', + 'COIN_SWAP_WITHDRAW': 'withdrawal', + 'OPTIONS_SETTLE_PROFIT': 'settlement', + 'DELIVERED_SETTELMENT': 'settlement', + 'WELCOME_BONUS': 'cashback', + 'CONTEST_REWARD': 'cashback', + 'COMMISSION_REBATE': 'rebate', + 'API_REBATE': 'rebate', + 'REFERRAL_KICKBACK': 'referral', + 'COMMISSION': 'commission', + }; + return this.safeString (ledgerType, type, type); + } + + sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { + const urls = this.urls as any; + if (!(api in urls['api'])) { + throw new NotSupported (this.id + ' does not have a testnet/sandbox URL for ' + api + ' endpoints'); + } + let url = this.urls['api'][api]; + url += '/' + path; + if (path === 'historicalTrades') { + if (this.apiKey) { + headers = { + 'X-MBX-APIKEY': this.apiKey, + }; + } else { + throw new AuthenticationError (this.id + ' historicalTrades endpoint requires `apiKey` credential'); + } + } + const userDataStream = (path === 'userDataStream') || (path === 'listenKey'); + if (userDataStream) { + if (this.apiKey) { + // v1 special case for userDataStream + headers = { + 'X-MBX-APIKEY': this.apiKey, + 'Content-Type': 'application/x-www-form-urlencoded', + }; + if (method !== 'GET') { + body = this.urlencode (params); + } + } else { + throw new AuthenticationError (this.id + ' userDataStream endpoint requires `apiKey` credential'); + } + } else if ((api === 'private') || (api === 'eapiPrivate') || (api === 'sapi' && path !== 'system/status') || (api === 'sapiV2') || (api === 'sapiV3') || (api === 'sapiV4') || (api === 'dapiPrivate') || (api === 'dapiPrivateV2') || (api === 'fapiPrivate') || (api === 'fapiPrivateV2') || (api === 'papi')) { + this.checkRequiredCredentials (); + if (method === 'POST' && ((path === 'order') || (path === 'sor/order'))) { + // inject in implicit API calls + const newClientOrderId = this.safeString (params, 'newClientOrderId'); + if (newClientOrderId === undefined) { + const isSpotOrMargin = (api.indexOf ('sapi') > -1 || api === 'private'); + const marketType = isSpotOrMargin ? 'spot' : 'future'; + const defaultId = (!isSpotOrMargin) ? 'x-xcKtGhcu' : 'x-R4BD3S82'; + const broker = this.safeValue (this.options, 'broker', {}); + const brokerId = this.safeString (broker, marketType, defaultId); + params['newClientOrderId'] = brokerId + this.uuid22 (); + } + } + let query = undefined; + // handle batchOrders + if ((path === 'batchOrders') && (method === 'POST')) { + const batchOrders = this.safeValue (params, 'batchOrders'); + const queryBatch = (this.json (batchOrders)); + params['batchOrders'] = queryBatch; + } + const defaultRecvWindow = this.safeInteger (this.options, 'recvWindow'); + let extendedParams = this.extend ({ + 'timestamp': this.nonce (), + }, params); + if (defaultRecvWindow !== undefined) { + extendedParams['recvWindow'] = defaultRecvWindow; + } + const recvWindow = this.safeInteger (params, 'recvWindow'); + if (recvWindow !== undefined) { + extendedParams['recvWindow'] = recvWindow; + } + if ((api === 'sapi') && (path === 'asset/dust')) { + query = this.urlencodeWithArrayRepeat (extendedParams); + } else if ((path === 'batchOrders') || (path.indexOf ('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path.indexOf ('staking') >= 0)) { + if ((method === 'DELETE') && (path === 'batchOrders')) { + const orderidlist = this.safeValue (extendedParams, 'orderidlist', []); + const origclientorderidlist = this.safeValue (extendedParams, 'origclientorderidlist', []); + extendedParams = this.omit (extendedParams, [ 'orderidlist', 'origclientorderidlist' ]); + query = this.rawencode (extendedParams); + const orderidlistLength = orderidlist.length; + const origclientorderidlistLength = origclientorderidlist.length; + if (orderidlistLength > 0) { + query = query + '&' + 'orderidlist=[' + orderidlist.join (',') + ']'; + } + if (origclientorderidlistLength > 0) { + query = query + '&' + 'origclientorderidlist=[' + origclientorderidlist.join (',') + ']'; + } + } else { + query = this.rawencode (extendedParams); + } + } else { + query = this.urlencode (extendedParams); + } + let signature = undefined; + if (this.secret.indexOf ('PRIVATE KEY') > -1) { + if (this.secret.length > 120) { + signature = this.encodeURIComponent (rsa (query, this.secret, sha256)); + } else { + signature = this.encodeURIComponent (eddsa (this.encode (query), this.secret, ed25519)); + } + } else { + signature = this.hmac (this.encode (query), this.encode (this.secret), sha256); + } + query += '&' + 'signature=' + signature; + headers = { + 'X-MBX-APIKEY': this.apiKey, + }; + if ((method === 'GET') || (method === 'DELETE')) { + url += '?' + query; + } else { + body = query; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + } else { + if (Object.keys (params).length) { + url += '?' + this.urlencode (params); + } + } + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; + } + + handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { + if ((code === 418) || (code === 429)) { + throw new DDoSProtection (this.id + ' ' + code.toString () + ' ' + reason + ' ' + body); + } + // error response in a form: { "code": -1013, "msg": "Invalid quantity." } + // following block cointains legacy checks against message patterns in "msg" property + // will switch "code" checks eventually, when we know all of them + if (code >= 400) { + if (body.indexOf ('Price * QTY is zero or less') >= 0) { + throw new InvalidOrder (this.id + ' order cost = amount * price is zero or less ' + body); + } + if (body.indexOf ('LOT_SIZE') >= 0) { + throw new InvalidOrder (this.id + ' order amount should be evenly divisible by lot size ' + body); + } + if (body.indexOf ('PRICE_FILTER') >= 0) { + throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid value in general, use this.priceToPrecision (symbol, amount) ' + body); + } + } + if (response === undefined) { + return undefined; // fallback to default error handler + } + // response in format {'msg': 'The coin does not exist.', 'success': true/false} + const success = this.safeValue (response, 'success', true); + if (!success) { + const messageNew = this.safeString (response, 'msg'); + let parsedMessage = undefined; + if (messageNew !== undefined) { + try { + parsedMessage = JSON.parse (messageNew); + } catch (e) { + // do nothing + parsedMessage = undefined; + } + if (parsedMessage !== undefined) { + response = parsedMessage; + } + } + } + const message = this.safeString (response, 'msg'); + if (message !== undefined) { + this.throwExactlyMatchedException (this.exceptions['exact'], message, this.id + ' ' + message); + this.throwBroadlyMatchedException (this.exceptions['broad'], message, this.id + ' ' + message); + } + // checks against error codes + const error = this.safeString (response, 'code'); + if (error !== undefined) { + // https://github.com/ccxt/ccxt/issues/6501 + // https://github.com/ccxt/ccxt/issues/7742 + if ((error === '200') || Precise.stringEquals (error, '0')) { + return undefined; + } + // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} + // despite that their message is very confusing, it is raised by Binance + // on a temporary ban, the API key is valid, but disabled for a while + if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) { + throw new DDoSProtection (this.id + ' ' + body); + } + const feedback = this.id + ' ' + body; + if (message === 'No need to change margin type.') { + // not an error + // https://github.com/ccxt/ccxt/issues/11268 + // https://github.com/ccxt/ccxt/pull/11624 + // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request + // binanceusdm {"code":-4046,"msg":"No need to change margin type."} + throw new MarginModeAlreadySet (feedback); + } + this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback); + throw new ExchangeError (feedback); + } + if (!success) { + throw new ExchangeError (this.id + ' ' + body); + } + if (Array.isArray (response)) { + // cancelOrders returns an array like this: [{"code":-2011,"msg":"Unknown order sent."}] + const arrayLength = response.length; + if (arrayLength === 1) { // when there's a single error we can throw, otherwise we have a partial success + const element = response[0]; + const errorCode = this.safeString (element, 'code'); + if (errorCode !== undefined) { + this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, this.id + ' ' + body); + } + } + } + return undefined; + } + + calculateRateLimiterCost (api, method, path, params, config = {}) { + if (('noCoin' in config) && !('coin' in params)) { + return config['noCoin']; + } else if (('noSymbol' in config) && !('symbol' in params)) { + return config['noSymbol']; + } else if (('noPoolId' in config) && !('poolId' in params)) { + return config['noPoolId']; + } else if (('byLimit' in config) && ('limit' in params)) { + const limit = params['limit']; + const byLimit = config['byLimit'] as any; + for (let i = 0; i < byLimit.length; i++) { + const entry = byLimit[i]; + if (limit <= entry[0]) { + return entry[1]; + } + } + } + return this.safeValue (config, 'cost', 1); + } + + async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined, config = {}, context = {}) { + const response = await this.fetch2 (path, api, method, params, headers, body, config); + // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} + if (api === 'private') { + this.options['hasAlreadyAuthenticatedSuccessfully'] = true; + } + return response; + } + + async modifyMarginHelper (symbol: string, amount, addOrReduce, params = {}) { + // used to modify isolated positions + let defaultType = this.safeString (this.options, 'defaultType', 'future'); + if (defaultType === 'spot') { + defaultType = 'future'; + } + const type = this.safeString (params, 'type', defaultType); + if ((type === 'margin') || (type === 'spot')) { + throw new NotSupported (this.id + ' add / reduce margin only supported with type future or delivery'); + } + await this.loadMarkets (); + const market = this.market (symbol); + amount = this.costToPrecision (symbol, amount); + const request = { + 'type': addOrReduce, + 'symbol': market['id'], + 'amount': amount, + }; + let method = undefined; + let code = undefined; + if (market['linear']) { + method = 'fapiPrivatePostPositionMargin'; + code = market['quote']; + } else { + method = 'dapiPrivatePostPositionMargin'; + code = market['base']; + } + const response = await this[method] (this.extend (request, params)); + // + // { + // "code": 200, + // "msg": "Successfully modify position margin.", + // "amount": 0.001, + // "type": 1 + // } + // + return this.extend (this.parseMarginModification (response, market), { + 'code': code, + }); + } + + parseMarginModification (data, market: Market = undefined) { + const rawType = this.safeInteger (data, 'type'); + const resultType = (rawType === 1) ? 'add' : 'reduce'; + const resultAmount = this.safeNumber (data, 'amount'); + const errorCode = this.safeString (data, 'code'); + const status = (errorCode === '200') ? 'ok' : 'failed'; + return { + 'info': data, + 'type': resultType, + 'amount': resultAmount, + 'code': undefined, + 'symbol': market['symbol'], + 'status': status, + }; + } + + async reduceMargin (symbol: string, amount, params = {}) { + /** + * @method + * @name binance#reduceMargin + * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-isolated-position-margin-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#modify-isolated-position-margin-trade + * @description remove margin from a position + * @param {string} symbol unified market symbol + * @param {float} amount the amount of margin to remove + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure} + */ + return await this.modifyMarginHelper (symbol, amount, 2, params); + } + + async addMargin (symbol: string, amount, params = {}) { + /** + * @method + * @name binance#addMargin + * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-isolated-position-margin-trade + * @see https://binance-docs.github.io/apidocs/futures/en/#modify-isolated-position-margin-trade + * @description add margin + * @param {string} symbol unified market symbol + * @param {float} amount amount of margin to add + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure} + */ + return await this.modifyMarginHelper (symbol, amount, 1, params); + } + + async fetchCrossBorrowRate (code: string, params = {}) { + /** + * @method + * @name binance#fetchCrossBorrowRate + * @description fetch the rate of interest to borrow a currency for margin trading + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-interest-rate-history-user_data + * @param {string} code unified currency code + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [borrow rate structure]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + // 'vipLevel': this.safeInteger (params, 'vipLevel'), + }; + const response = await this.sapiGetMarginInterestRateHistory (this.extend (request, params)); + // + // [ + // { + // "asset": "USDT", + // "timestamp": 1638230400000, + // "dailyInterestRate": "0.0006", + // "vipLevel": 0 + // }, + // ] + // + const rate = this.safeValue (response, 0); + return this.parseBorrowRate (rate); + } + + async fetchBorrowRateHistory (code: string, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchBorrowRateHistory + * @description retrieves a history of a currencies borrow interest rate at specific time slots + * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-interest-rate-history-user_data + * @param {string} code unified currency code + * @param {int} [since] timestamp for the earliest borrow rate + * @param {int} [limit] the maximum number of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} an array of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} + */ + await this.loadMarkets (); + if (limit === undefined) { + limit = 93; + } else if (limit > 93) { + // Binance API says the limit is 100, but "Illegal characters found in a parameter." is returned when limit is > 93 + throw new BadRequest (this.id + ' fetchBorrowRateHistory() limit parameter cannot exceed 92'); + } + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + 'limit': limit, + }; + if (since !== undefined) { + request['startTime'] = since; + const endTime = this.sum (since, limit * 86400000) - 1; // required when startTime is further than 93 days in the past + const now = this.milliseconds (); + request['endTime'] = Math.min (endTime, now); // cannot have an endTime later than current time + } + const response = await this.sapiGetMarginInterestRateHistory (this.extend (request, params)); + // + // [ + // { + // "asset": "USDT", + // "timestamp": 1638230400000, + // "dailyInterestRate": "0.0006", + // "vipLevel": 0 + // }, + // ] + // + return this.parseBorrowRateHistory (response, code, since, limit); + } + + parseBorrowRateHistory (response, code, since, limit) { + const result = []; + for (let i = 0; i < response.length; i++) { + const item = response[i]; + const borrowRate = this.parseBorrowRate (item); + result.push (borrowRate); + } + const sorted = this.sortBy (result, 'timestamp'); + return this.filterByCurrencySinceLimit (sorted, code, since, limit); + } + + parseBorrowRate (info, currency: Currency = undefined) { + // + // { + // "asset": "USDT", + // "timestamp": 1638230400000, + // "dailyInterestRate": "0.0006", + // "vipLevel": 0 + // } + // + const timestamp = this.safeInteger (info, 'timestamp'); + const currencyId = this.safeString (info, 'asset'); + return { + 'currency': this.safeCurrencyCode (currencyId, currency), + 'rate': this.safeNumber (info, 'dailyInterestRate'), + 'period': 86400000, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'info': info, + }; + } + + async createGiftCode (code: string, amount, params = {}) { + /** + * @method + * @name binance#createGiftCode + * @description create gift code + * @see https://binance-docs.github.io/apidocs/spot/en/#create-a-single-token-gift-card-user_data + * @param {string} code gift code + * @param {float} amount amount of currency for the gift + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} The gift code id, code, currency and amount + */ + await this.loadMarkets (); + const currency = this.currency (code); + // ensure you have enough token in your funding account before calling this code + const request = { + 'token': currency['id'], + 'amount': amount, + }; + const response = await this.sapiPostGiftcardCreateCode (this.extend (request, params)); + // + // { + // "code": "000000", + // "message": "success", + // "data": { referenceNo: "0033002404219823", code: "AP6EXTLKNHM6CEX7" }, + // "success": true + // } + // + const data = this.safeValue (response, 'data'); + const giftcardCode = this.safeString (data, 'code'); + const id = this.safeString (data, 'referenceNo'); + return { + 'info': response, + 'id': id, + 'code': giftcardCode, + 'currency': code, + 'amount': amount, + }; + } + + async redeemGiftCode (giftcardCode, params = {}) { + /** + * @method + * @name binance#redeemGiftCode + * @description redeem gift code + * @see https://binance-docs.github.io/apidocs/spot/en/#redeem-a-binance-gift-card-user_data + * @param {string} giftcardCode + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} response from the exchange + */ + const request = { + 'code': giftcardCode, + }; + const response = await this.sapiPostGiftcardRedeemCode (this.extend (request, params)); + // + // { + // "code": "000000", + // "message": "success", + // "data": { + // "referenceNo": "0033002404219823", + // "identityNo": "10316431732801474560" + // }, + // "success": true + // } + // + return response; + } + + async verifyGiftCode (id: string, params = {}) { + /** + * @method + * @name binance#verifyGiftCode + * @description verify gift code + * @see https://binance-docs.github.io/apidocs/spot/en/#verify-binance-gift-card-by-gift-card-number-user_data + * @param {string} id reference number id + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} response from the exchange + */ + const request = { + 'referenceNo': id, + }; + const response = await this.sapiGetGiftcardVerify (this.extend (request, params)); + // + // { + // "code": "000000", + // "message": "success", + // "data": { valid: true }, + // "success": true + // } + // + return response; + } + + async fetchBorrowInterest (code: Str = undefined, symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchBorrowInterest + * @description fetch the interest owed by the user for borrowing currency for margin trading + * @see https://binance-docs.github.io/apidocs/spot/en/#get-interest-history-user_data + * @param {string} code unified currency code + * @param {string} symbol unified market symbol when fetch interest in isolated markets + * @param {int} [since] the earliest time in ms to fetch borrrow interest for + * @param {int} [limit] the maximum number of structures to retrieve + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object[]} a list of [borrow interest structures]{@link https://docs.ccxt.com/#/?id=borrow-interest-structure} + */ + await this.loadMarkets (); + const request = {}; + let market = undefined; + if (code !== undefined) { + const currency = this.currency (code); + request['asset'] = currency['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + request['size'] = limit; + } + if (symbol !== undefined) { // Isolated + market = this.market (symbol); + request['isolatedSymbol'] = market['id']; + } + const response = await this.sapiGetMarginInterestHistory (this.extend (request, params)); + // + // { + // "rows":[ + // { + // "isolatedSymbol": "BNBUSDT", // isolated symbol, will not be returned for crossed margin + // "asset": "BNB", + // "interest": "0.02414667", + // "interestAccuredTime": 1566813600000, + // "interestRate": "0.01600000", + // "principal": "36.22000000", + // "type": "ON_BORROW" + // } + // ], + // "total": 1 + // } + // + const rows = this.safeValue (response, 'rows'); + const interest = this.parseBorrowInterests (rows, market); + return this.filterByCurrencySinceLimit (interest, code, since, limit); + } + + parseBorrowInterest (info, market: Market = undefined) { + const symbol = this.safeString (info, 'isolatedSymbol'); + const timestamp = this.safeNumber (info, 'interestAccuredTime'); + const marginMode = (symbol === undefined) ? 'cross' : 'isolated'; + return { + 'account': (symbol === undefined) ? 'cross' : symbol, + 'symbol': symbol, + 'marginMode': marginMode, + 'currency': this.safeCurrencyCode (this.safeString (info, 'asset')), + 'interest': this.safeNumber (info, 'interest'), + 'interestRate': this.safeNumber (info, 'interestRate'), + 'amountBorrowed': this.safeNumber (info, 'principal'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'info': info, + }; + } + + async repayCrossMargin (code: string, amount, params = {}) { + /** + * @method + * @name binance#repayCrossMargin + * @description repay borrowed margin and interest + * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-repay-margin + * @param {string} code unified currency code of the currency to repay + * @param {float} amount the amount to repay + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + 'amount': this.currencyToPrecision (code, amount), + 'isIsolated': 'FALSE', + }; + const response = await this.sapiPostMarginRepay (this.extend (request, params)); + // + // { + // "tranId": 108988250265, + // "clientTag":"" + // } + // + return this.parseMarginLoan (response, currency); + } + + async repayIsolatedMargin (symbol: string, code: string, amount, params = {}) { + /** + * @method + * @name binance#repayIsolatedMargin + * @description repay borrowed margin and interest + * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-repay-margin + * @param {string} symbol unified market symbol, required for isolated margin + * @param {string} code unified currency code of the currency to repay + * @param {float} amount the amount to repay + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const market = this.market (symbol); + const request = { + 'asset': currency['id'], + 'amount': this.currencyToPrecision (code, amount), + 'symbol': market['id'], + 'isIsolated': 'TRUE', + }; + const response = await this.sapiPostMarginRepay (this.extend (request, params)); + // + // { + // "tranId": 108988250265, + // "clientTag":"" + // } + // + return this.parseMarginLoan (response, currency); + } + + async borrowCrossMargin (code: string, amount, params = {}) { + /** + * @method + * @name binance#borrowCrossMargin + * @description create a loan to borrow margin + * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-margin + * @param {string} code unified currency code of the currency to borrow + * @param {float} amount the amount to borrow + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const request = { + 'asset': currency['id'], + 'amount': this.currencyToPrecision (code, amount), + 'isIsolated': 'FALSE', + }; + const response = await this.sapiPostMarginLoan (this.extend (request, params)); + // + // { + // "tranId": 108988250265, + // "clientTag":"" + // } + // + return this.parseMarginLoan (response, currency); + } + + async borrowIsolatedMargin (symbol: string, code: string, amount, params = {}) { + /** + * @method + * @name binance#borrowIsolatedMargin + * @description create a loan to borrow margin + * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-margin + * @param {string} symbol unified market symbol, required for isolated margin + * @param {string} code unified currency code of the currency to borrow + * @param {float} amount the amount to borrow + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} + */ + await this.loadMarkets (); + const currency = this.currency (code); + const market = this.market (symbol); + const request = { + 'asset': currency['id'], + 'amount': this.currencyToPrecision (code, amount), + 'symbol': market['id'], + 'isIsolated': 'TRUE', + }; + const response = await this.sapiPostMarginLoan (this.extend (request, params)); + // + // { + // "tranId": 108988250265, + // "clientTag":"" + // } + // + return this.parseMarginLoan (response, currency); + } + + parseMarginLoan (info, currency: Currency = undefined) { + // + // { + // "tranId": 108988250265, + // "clientTag":"" + // } + // + return { + 'id': this.safeInteger (info, 'tranId'), + 'currency': this.safeCurrencyCode (undefined, currency), + 'amount': undefined, + 'symbol': undefined, + 'timestamp': undefined, + 'datetime': undefined, + 'info': info, + }; + } + + async fetchOpenInterestHistory (symbol: string, timeframe = '5m', since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchOpenInterestHistory + * @description Retrieves the open interest history of a currency + * @see https://binance-docs.github.io/apidocs/delivery/en/#open-interest-statistics + * @see https://binance-docs.github.io/apidocs/futures/en/#open-interest-statistics + * @param {string} symbol Unified CCXT market symbol + * @param {string} timeframe "5m","15m","30m","1h","2h","4h","6h","12h", or "1d" + * @param {int} [since] the time(ms) of the earliest record to retrieve as a unix timestamp + * @param {int} [limit] default 30, max 500 + * @param {object} [params] exchange specific parameters + * @param {int} [params.until] the time(ms) of the latest record to retrieve as a unix timestamp + * @returns {object} an array of [open interest structure]{@link https://docs.ccxt.com/#/?id=open-interest-structure} + */ + if (timeframe === '1m') { + throw new BadRequest (this.id + 'fetchOpenInterestHistory cannot use the 1m timeframe'); + } + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchOpenInterestHistory', 'paginate', false); + if (paginate) { + return await this.fetchPaginatedCallDeterministic ('fetchOpenInterestHistory', symbol, since, limit, timeframe, params, 500) as OpenInterest[]; + } + const market = this.market (symbol); + const request = { + 'period': this.safeString (this.timeframes, timeframe, timeframe), + }; + if (limit !== undefined) { + request['limit'] = limit; + } + const symbolKey = market['linear'] ? 'symbol' : 'pair'; + request[symbolKey] = market['id']; + if (market['inverse']) { + request['contractType'] = this.safeString (params, 'contractType', 'CURRENT_QUARTER'); + } + if (since !== undefined) { + request['startTime'] = since; + } + const until = this.safeInteger2 (params, 'until', 'till'); // unified in milliseconds + const endTime = this.safeInteger (params, 'endTime', until); // exchange-specific in milliseconds + params = this.omit (params, [ 'endTime', 'until', 'till' ]); + if (endTime) { + request['endTime'] = endTime; + } else if (since) { + if (limit === undefined) { + limit = 30; // Exchange default + } + const duration = this.parseTimeframe (timeframe); + request['endTime'] = this.sum (since, duration * limit * 1000); + } + let method = 'fapiDataGetOpenInterestHist'; + if (market['inverse']) { + method = 'dapiDataGetOpenInterestHist'; + } + const response = await this[method] (this.extend (request, params)); + // + // [ + // { + // "symbol":"BTCUSDT", + // "sumOpenInterest":"75375.61700000", + // "sumOpenInterestValue":"3248828883.71251440", + // "timestamp":1642179900000 + // }, + // ... + // ] + // + return this.parseOpenInterests (response, market, since, limit); + } + + async fetchOpenInterest (symbol: string, params = {}) { + /** + * @method + * @name binance#fetchOpenInterest + * @description retrieves the open interest of a contract trading pair + * @see https://binance-docs.github.io/apidocs/futures/en/#open-interest + * @see https://binance-docs.github.io/apidocs/delivery/en/#open-interest + * @see https://binance-docs.github.io/apidocs/voptions/en/#open-interest + * @param {string} symbol unified CCXT market symbol + * @param {object} [params] exchange specific parameters + * @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const request = {}; + if (market['option']) { + request['underlyingAsset'] = market['baseId']; + request['expiration'] = this.yymmdd (market['expiry']); + } else { + request['symbol'] = market['id']; + } + let method = 'fapiPublicGetOpenInterest'; + if (market['option']) { + method = 'eapiPublicGetOpenInterest'; + } else if (market['inverse']) { + method = 'dapiPublicGetOpenInterest'; + } + const response = await this[method] (this.extend (request, params)); + // + // futures (fapi) + // + // { + // "symbol": "ETHUSDT_230331", + // "openInterest": "23581.677", + // "time": 1677356872265 + // } + // + // futures (dapi) + // + // { + // "symbol": "ETHUSD_PERP", + // "pair": "ETHUSD", + // "openInterest": "26542436", + // "contractType": "PERPETUAL", + // "time": 1677360272224 + // } + // + // options (eapi) + // + // [ + // { + // "symbol": "ETH-230225-1625-C", + // "sumOpenInterest": "460.50", + // "sumOpenInterestUsd": "734957.4358092150", + // "timestamp": "1677304860000" + // } + // ] + // + if (market['option']) { + const result = this.parseOpenInterests (response, market); + for (let i = 0; i < result.length; i++) { + const item = result[i]; + if (item['symbol'] === symbol) { + return item; + } + } + } else { + return this.parseOpenInterest (response, market); + } + } + + parseOpenInterest (interest, market: Market = undefined) { + const timestamp = this.safeInteger2 (interest, 'timestamp', 'time'); + const id = this.safeString (interest, 'symbol'); + const amount = this.safeNumber2 (interest, 'sumOpenInterest', 'openInterest'); + const value = this.safeNumber2 (interest, 'sumOpenInterestValue', 'sumOpenInterestUsd'); + // Inverse returns the number of contracts different from the base or quote volume in this case + // compared with https://www.binance.com/en/futures/funding-history/quarterly/4 + return this.safeOpenInterest ({ + 'symbol': this.safeSymbol (id, market, undefined, 'contract'), + 'baseVolume': market['inverse'] ? undefined : amount, // deprecated + 'quoteVolume': value, // deprecated + 'openInterestAmount': amount, + 'openInterestValue': value, + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + 'info': interest, + }, market); + } + + async fetchMyLiquidations (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { + /** + * @method + * @name binance#fetchMyLiquidations + * @description retrieves the users liquidated positions + * @see https://binance-docs.github.io/apidocs/spot/en/#get-force-liquidation-record-user_data + * @see https://binance-docs.github.io/apidocs/futures/en/#user-39-s-force-orders-user_data + * @see https://binance-docs.github.io/apidocs/delivery/en/#user-39-s-force-orders-user_data + * @param {string} [symbol] unified CCXT market symbol + * @param {int} [since] the earliest time in ms to fetch liquidations for + * @param {int} [limit] the maximum number of liquidation structures to retrieve + * @param {object} [params] exchange specific parameters for the binance api endpoint + * @param {int} [params.until] timestamp in ms of the latest liquidation + * @param {boolean} [params.paginate] *spot only* default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) + * @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure} + */ + await this.loadMarkets (); + let paginate = false; + [ paginate, params ] = this.handleOptionAndParams (params, 'fetchMyLiquidations', 'paginate'); + if (paginate) { + return await this.fetchPaginatedCallIncremental ('fetchMyLiquidations', symbol, since, limit, params, 'current', 100) as Liquidation[]; + } + let market = undefined; + if (symbol !== undefined) { + market = this.market (symbol); + } + let type = undefined; + [ type, params ] = this.handleMarketTypeAndParams ('fetchMyLiquidations', market, params); + let subType = undefined; + [ subType, params ] = this.handleSubTypeAndParams ('fetchMyLiquidations', market, params, 'linear'); + let request = {}; + if (type !== 'spot') { + request['autoCloseType'] = 'LIQUIDATION'; + } + if (market !== undefined) { + const symbolKey = market['spot'] ? 'isolatedSymbol' : 'symbol'; + request[symbolKey] = market['id']; + } + if (since !== undefined) { + request['startTime'] = since; + } + if (limit !== undefined) { + if (type === 'spot') { + request['size'] = limit; + } else { + request['limit'] = limit; + } + } + [ request, params ] = this.handleUntilOption ('endTime', request, params); + let response = undefined; + if (type === 'spot') { + response = await this.sapiGetMarginForceLiquidationRec (this.extend (request, params)); + } else if (subType === 'linear') { + response = await this.fapiPrivateGetForceOrders (this.extend (request, params)); + } else if (subType === 'inverse') { + response = await this.dapiPrivateGetForceOrders (this.extend (request, params)); + } else { + throw new NotSupported (this.id + ' fetchMyLiquidations() does not support ' + market['type'] + ' markets'); + } + // + // margin + // + // { + // "rows": [ + // { + // "avgPrice": "0.00388359", + // "executedQty": "31.39000000", + // "orderId": 180015097, + // "price": "0.00388110", + // "qty": "31.39000000", + // "side": "SELL", + // "symbol": "BNBBTC", + // "timeInForce": "GTC", + // "isIsolated": true, + // "updatedTime": 1558941374745 + // } + // ], + // "total": 1 + // } + // + // linear + // + // [ + // { + // "orderId": 6071832819, + // "symbol": "BTCUSDT", + // "status": "FILLED", + // "clientOrderId": "autoclose-1596107620040000020", + // "price": "10871.09", + // "avgPrice": "10913.21000", + // "origQty": "0.001", + // "executedQty": "0.001", + // "cumQuote": "10.91321", + // "timeInForce": "IOC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "SELL", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "origType": "LIMIT", + // "time": 1596107620044, + // "updateTime": 1596107620087 + // }, + // ] + // + // inverse + // + // [ + // { + // "orderId": 165123080, + // "symbol": "BTCUSD_200925", + // "pair": "BTCUSD", + // "status": "FILLED", + // "clientOrderId": "autoclose-1596542005017000006", + // "price": "11326.9", + // "avgPrice": "11326.9", + // "origQty": "1", + // "executedQty": "1", + // "cumBase": "0.00882854", + // "timeInForce": "IOC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "SELL", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, + // "origType": "LIMIT", + // "time": 1596542005019, + // "updateTime": 1596542005050 + // }, + // ] + // + const liquidations = this.safeValue (response, 'rows', response); + return this.parseLiquidations (liquidations, market, since, limit); + } + + parseLiquidation (liquidation, market: Market = undefined) { + // + // margin + // + // { + // "avgPrice": "0.00388359", + // "executedQty": "31.39000000", + // "orderId": 180015097, + // "price": "0.00388110", + // "qty": "31.39000000", + // "side": "SELL", + // "symbol": "BNBBTC", + // "timeInForce": "GTC", + // "isIsolated": true, + // "updatedTime": 1558941374745 + // } + // + // linear + // + // { + // "orderId": 6071832819, + // "symbol": "BTCUSDT", + // "status": "FILLED", + // "clientOrderId": "autoclose-1596107620040000020", + // "price": "10871.09", + // "avgPrice": "10913.21000", + // "origQty": "0.001", + // "executedQty": "0.001", + // "cumQuote": "10.91321", + // "timeInForce": "IOC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "SELL", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "origType": "LIMIT", + // "time": 1596107620044, + // "updateTime": 1596107620087 + // } + // + // inverse + // + // { + // "orderId": 165123080, + // "symbol": "BTCUSD_200925", + // "pair": "BTCUSD", + // "status": "FILLED", + // "clientOrderId": "autoclose-1596542005017000006", + // "price": "11326.9", + // "avgPrice": "11326.9", + // "origQty": "1", + // "executedQty": "1", + // "cumBase": "0.00882854", + // "timeInForce": "IOC", + // "type": "LIMIT", + // "reduceOnly": false, + // "closePosition": false, + // "side": "SELL", + // "positionSide": "BOTH", + // "stopPrice": "0", + // "workingType": "CONTRACT_PRICE", + // "priceProtect": false, + // "origType": "LIMIT", + // "time": 1596542005019, + // "updateTime": 1596542005050 + // } + // + const marketId = this.safeString (liquidation, 'symbol'); + const timestamp = this.safeInteger2 (liquidation, 'updatedTime', 'updateTime'); + return this.safeLiquidation ({ + 'info': liquidation, + 'symbol': this.safeSymbol (marketId, market), + 'contracts': this.safeNumber (liquidation, 'executedQty'), + 'contractSize': this.safeNumber (market, 'contractSize'), + 'price': this.safeNumber (liquidation, 'avgPrice'), + 'baseValue': this.safeNumber (liquidation, 'cumBase'), + 'quoteValue': this.safeNumber (liquidation, 'cumQuote'), + 'timestamp': timestamp, + 'datetime': this.iso8601 (timestamp), + }); + } + + async fetchGreeks (symbol: string, params = {}): Promise { + /** + * @method + * @name binance#fetchGreeks + * @description fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract + * @see https://binance-docs.github.io/apidocs/voptions/en/#option-mark-price + * @param {string} symbol unified symbol of the market to fetch greeks for + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [greeks structure]{@link https://docs.ccxt.com/#/?id=greeks-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'symbol': market['id'], + }; + const response = await this.eapiPublicGetMark (this.extend (request, params)); + // + // [ + // { + // "symbol": "BTC-231229-40000-C", + // "markPrice": "2012", + // "bidIV": "0.60236275", + // "askIV": "0.62267244", + // "markIV": "0.6125176", + // "delta": "0.39111646", + // "theta": "-32.13948531", + // "gamma": "0.00004656", + // "vega": "51.70062218", + // "highPriceLimit": "6474", + // "lowPriceLimit": "5" + // } + // ] + // + return this.parseGreeks (response[0], market); + } + + parseGreeks (greeks, market: Market = undefined) { + // + // { + // "symbol": "BTC-231229-40000-C", + // "markPrice": "2012", + // "bidIV": "0.60236275", + // "askIV": "0.62267244", + // "markIV": "0.6125176", + // "delta": "0.39111646", + // "theta": "-32.13948531", + // "gamma": "0.00004656", + // "vega": "51.70062218", + // "highPriceLimit": "6474", + // "lowPriceLimit": "5" + // } + // + const marketId = this.safeString (greeks, 'symbol'); + const symbol = this.safeSymbol (marketId, market); + return { + 'symbol': symbol, + 'timestamp': undefined, + 'datetime': undefined, + 'delta': this.safeNumber (greeks, 'delta'), + 'gamma': this.safeNumber (greeks, 'gamma'), + 'theta': this.safeNumber (greeks, 'theta'), + 'vega': this.safeNumber (greeks, 'vega'), + 'rho': undefined, + 'bidSize': undefined, + 'askSize': undefined, + 'bidImpliedVolatility': this.safeNumber (greeks, 'bidIV'), + 'askImpliedVolatility': this.safeNumber (greeks, 'askIV'), + 'markImpliedVolatility': this.safeNumber (greeks, 'markIV'), + 'bidPrice': undefined, + 'askPrice': undefined, + 'markPrice': this.safeNumber (greeks, 'markPrice'), + 'lastPrice': undefined, + 'underlyingPrice': undefined, + 'info': greeks, + }; + } +} From 134af6c8773ac096308226f084f50975cc83fba9 Mon Sep 17 00:00:00 2001 From: tlauria Date: Thu, 15 Feb 2024 11:30:18 +0100 Subject: [PATCH 2/2] fix: base methods --- ts/src/abstract/youngplatform.ts | 681 +- ts/src/youngplatform.ts | 10077 +++-------------------------- 2 files changed, 772 insertions(+), 9986 deletions(-) diff --git a/ts/src/abstract/youngplatform.ts b/ts/src/abstract/youngplatform.ts index 22c71a9adef49..c0f41e165c234 100644 --- a/ts/src/abstract/youngplatform.ts +++ b/ts/src/abstract/youngplatform.ts @@ -9,669 +9,24 @@ import { implicitReturnType } from '../base/types.js'; import { Exchange as _Exchange } from '../base/Exchange.js'; interface Exchange { - sapiGetSystemStatus (params?: {}): Promise; - sapiGetAccountSnapshot (params?: {}): Promise; - sapiGetMarginAsset (params?: {}): Promise; - sapiGetMarginPair (params?: {}): Promise; - sapiGetMarginAllAssets (params?: {}): Promise; - sapiGetMarginAllPairs (params?: {}): Promise; - sapiGetMarginPriceIndex (params?: {}): Promise; - sapiGetAssetAssetDividend (params?: {}): Promise; - sapiGetAssetDribblet (params?: {}): Promise; - sapiGetAssetTransfer (params?: {}): Promise; - sapiGetAssetAssetDetail (params?: {}): Promise; - sapiGetAssetTradeFee (params?: {}): Promise; - sapiGetAssetLedgerTransferCloudMiningQueryByPage (params?: {}): Promise; - sapiGetAssetConvertTransferQueryByPage (params?: {}): Promise; - sapiGetAssetWalletBalance (params?: {}): Promise; - sapiGetAssetCustodyTransferHistory (params?: {}): Promise; - sapiGetMarginLoan (params?: {}): Promise; - sapiGetMarginRepay (params?: {}): Promise; - sapiGetMarginAccount (params?: {}): Promise; - sapiGetMarginTransfer (params?: {}): Promise; - sapiGetMarginInterestHistory (params?: {}): Promise; - sapiGetMarginForceLiquidationRec (params?: {}): Promise; - sapiGetMarginOrder (params?: {}): Promise; - sapiGetMarginOpenOrders (params?: {}): Promise; - sapiGetMarginAllOrders (params?: {}): Promise; - sapiGetMarginMyTrades (params?: {}): Promise; - sapiGetMarginMaxBorrowable (params?: {}): Promise; - sapiGetMarginMaxTransferable (params?: {}): Promise; - sapiGetMarginTradeCoeff (params?: {}): Promise; - sapiGetMarginIsolatedTransfer (params?: {}): Promise; - sapiGetMarginIsolatedAccount (params?: {}): Promise; - sapiGetMarginIsolatedPair (params?: {}): Promise; - sapiGetMarginIsolatedAllPairs (params?: {}): Promise; - sapiGetMarginIsolatedAccountLimit (params?: {}): Promise; - sapiGetMarginInterestRateHistory (params?: {}): Promise; - sapiGetMarginOrderList (params?: {}): Promise; - sapiGetMarginAllOrderList (params?: {}): Promise; - sapiGetMarginOpenOrderList (params?: {}): Promise; - sapiGetMarginCrossMarginData (params?: {}): Promise; - sapiGetMarginIsolatedMarginData (params?: {}): Promise; - sapiGetMarginIsolatedMarginTier (params?: {}): Promise; - sapiGetMarginRateLimitOrder (params?: {}): Promise; - sapiGetMarginDribblet (params?: {}): Promise; - sapiGetMarginDust (params?: {}): Promise; - sapiGetMarginCrossMarginCollateralRatio (params?: {}): Promise; - sapiGetMarginExchangeSmallLiability (params?: {}): Promise; - sapiGetMarginExchangeSmallLiabilityHistory (params?: {}): Promise; - sapiGetMarginNextHourlyInterestRate (params?: {}): Promise; - sapiGetMarginCapitalFlow (params?: {}): Promise; - sapiGetMarginDelistSchedule (params?: {}): Promise; - sapiGetMarginAvailableInventory (params?: {}): Promise; - sapiGetMarginLeverageBracket (params?: {}): Promise; - sapiGetLoanVipLoanableData (params?: {}): Promise; - sapiGetLoanVipCollateralData (params?: {}): Promise; - sapiGetLoanVipRequestData (params?: {}): Promise; - sapiGetLoanVipRequestInterestRate (params?: {}): Promise; - sapiGetLoanIncome (params?: {}): Promise; - sapiGetLoanOngoingOrders (params?: {}): Promise; - sapiGetLoanLtvAdjustmentHistory (params?: {}): Promise; - sapiGetLoanBorrowHistory (params?: {}): Promise; - sapiGetLoanRepayHistory (params?: {}): Promise; - sapiGetLoanLoanableData (params?: {}): Promise; - sapiGetLoanCollateralData (params?: {}): Promise; - sapiGetLoanRepayCollateralRate (params?: {}): Promise; - sapiGetLoanFlexibleOngoingOrders (params?: {}): Promise; - sapiGetLoanFlexibleBorrowHistory (params?: {}): Promise; - sapiGetLoanFlexibleRepayHistory (params?: {}): Promise; - sapiGetLoanFlexibleLtvAdjustmentHistory (params?: {}): Promise; - sapiGetLoanFlexibleLoanableData (params?: {}): Promise; - sapiGetLoanFlexibleCollateralData (params?: {}): Promise; - sapiGetLoanVipOngoingOrders (params?: {}): Promise; - sapiGetLoanVipRepayHistory (params?: {}): Promise; - sapiGetLoanVipCollateralAccount (params?: {}): Promise; - sapiGetFiatOrders (params?: {}): Promise; - sapiGetFiatPayments (params?: {}): Promise; - sapiGetFuturesTransfer (params?: {}): Promise; - sapiGetFuturesHistDataLink (params?: {}): Promise; - sapiGetRebateTaxQuery (params?: {}): Promise; - sapiGetCapitalConfigGetall (params?: {}): Promise; - sapiGetCapitalDepositAddress (params?: {}): Promise; - sapiGetCapitalDepositAddressList (params?: {}): Promise; - sapiGetCapitalDepositHisrec (params?: {}): Promise; - sapiGetCapitalDepositSubAddress (params?: {}): Promise; - sapiGetCapitalDepositSubHisrec (params?: {}): Promise; - sapiGetCapitalWithdrawHistory (params?: {}): Promise; - sapiGetCapitalContractConvertibleCoins (params?: {}): Promise; - sapiGetConvertTradeFlow (params?: {}): Promise; - sapiGetConvertExchangeInfo (params?: {}): Promise; - sapiGetConvertAssetInfo (params?: {}): Promise; - sapiGetConvertOrderStatus (params?: {}): Promise; - sapiGetAccountStatus (params?: {}): Promise; - sapiGetAccountApiTradingStatus (params?: {}): Promise; - sapiGetAccountApiRestrictionsIpRestriction (params?: {}): Promise; - sapiGetBnbBurn (params?: {}): Promise; - sapiGetSubAccountFuturesAccount (params?: {}): Promise; - sapiGetSubAccountFuturesAccountSummary (params?: {}): Promise; - sapiGetSubAccountFuturesPositionRisk (params?: {}): Promise; - sapiGetSubAccountFuturesInternalTransfer (params?: {}): Promise; - sapiGetSubAccountList (params?: {}): Promise; - sapiGetSubAccountMarginAccount (params?: {}): Promise; - sapiGetSubAccountMarginAccountSummary (params?: {}): Promise; - sapiGetSubAccountSpotSummary (params?: {}): Promise; - sapiGetSubAccountStatus (params?: {}): Promise; - sapiGetSubAccountSubTransferHistory (params?: {}): Promise; - sapiGetSubAccountTransferSubUserHistory (params?: {}): Promise; - sapiGetSubAccountUniversalTransfer (params?: {}): Promise; - sapiGetSubAccountApiRestrictionsIpRestrictionThirdPartyList (params?: {}): Promise; - sapiGetSubAccountTransactionStatistics (params?: {}): Promise; - sapiGetSubAccountSubAccountApiIpRestriction (params?: {}): Promise; - sapiGetManagedSubaccountAsset (params?: {}): Promise; - sapiGetManagedSubaccountAccountSnapshot (params?: {}): Promise; - sapiGetManagedSubaccountQueryTransLogForInvestor (params?: {}): Promise; - sapiGetManagedSubaccountQueryTransLogForTradeParent (params?: {}): Promise; - sapiGetManagedSubaccountFetchFutureAsset (params?: {}): Promise; - sapiGetManagedSubaccountMarginAsset (params?: {}): Promise; - sapiGetManagedSubaccountInfo (params?: {}): Promise; - sapiGetManagedSubaccountDepositAddress (params?: {}): Promise; - sapiGetManagedSubaccountQueryTransLog (params?: {}): Promise; - sapiGetLendingDailyProductList (params?: {}): Promise; - sapiGetLendingDailyUserLeftQuota (params?: {}): Promise; - sapiGetLendingDailyUserRedemptionQuota (params?: {}): Promise; - sapiGetLendingDailyTokenPosition (params?: {}): Promise; - sapiGetLendingUnionAccount (params?: {}): Promise; - sapiGetLendingUnionPurchaseRecord (params?: {}): Promise; - sapiGetLendingUnionRedemptionRecord (params?: {}): Promise; - sapiGetLendingUnionInterestHistory (params?: {}): Promise; - sapiGetLendingProjectList (params?: {}): Promise; - sapiGetLendingProjectPositionList (params?: {}): Promise; - sapiGetMiningPubAlgoList (params?: {}): Promise; - sapiGetMiningPubCoinList (params?: {}): Promise; - sapiGetMiningWorkerDetail (params?: {}): Promise; - sapiGetMiningWorkerList (params?: {}): Promise; - sapiGetMiningPaymentList (params?: {}): Promise; - sapiGetMiningStatisticsUserStatus (params?: {}): Promise; - sapiGetMiningStatisticsUserList (params?: {}): Promise; - sapiGetMiningPaymentUid (params?: {}): Promise; - sapiGetBswapPools (params?: {}): Promise; - sapiGetBswapLiquidity (params?: {}): Promise; - sapiGetBswapLiquidityOps (params?: {}): Promise; - sapiGetBswapQuote (params?: {}): Promise; - sapiGetBswapSwap (params?: {}): Promise; - sapiGetBswapPoolConfigure (params?: {}): Promise; - sapiGetBswapAddLiquidityPreview (params?: {}): Promise; - sapiGetBswapRemoveLiquidityPreview (params?: {}): Promise; - sapiGetBswapUnclaimedRewards (params?: {}): Promise; - sapiGetBswapClaimedHistory (params?: {}): Promise; - sapiGetBlvtTokenInfo (params?: {}): Promise; - sapiGetBlvtSubscribeRecord (params?: {}): Promise; - sapiGetBlvtRedeemRecord (params?: {}): Promise; - sapiGetBlvtUserLimit (params?: {}): Promise; - sapiGetApiReferralIfNewUser (params?: {}): Promise; - sapiGetApiReferralCustomization (params?: {}): Promise; - sapiGetApiReferralUserCustomization (params?: {}): Promise; - sapiGetApiReferralRebateRecentRecord (params?: {}): Promise; - sapiGetApiReferralRebateHistoricalRecord (params?: {}): Promise; - sapiGetApiReferralKickbackRecentRecord (params?: {}): Promise; - sapiGetApiReferralKickbackHistoricalRecord (params?: {}): Promise; - sapiGetBrokerSubAccountApi (params?: {}): Promise; - sapiGetBrokerSubAccount (params?: {}): Promise; - sapiGetBrokerSubAccountApiCommissionFutures (params?: {}): Promise; - sapiGetBrokerSubAccountApiCommissionCoinFutures (params?: {}): Promise; - sapiGetBrokerInfo (params?: {}): Promise; - sapiGetBrokerTransfer (params?: {}): Promise; - sapiGetBrokerTransferFutures (params?: {}): Promise; - sapiGetBrokerRebateRecentRecord (params?: {}): Promise; - sapiGetBrokerRebateHistoricalRecord (params?: {}): Promise; - sapiGetBrokerSubAccountBnbBurnStatus (params?: {}): Promise; - sapiGetBrokerSubAccountDepositHist (params?: {}): Promise; - sapiGetBrokerSubAccountSpotSummary (params?: {}): Promise; - sapiGetBrokerSubAccountMarginSummary (params?: {}): Promise; - sapiGetBrokerSubAccountFuturesSummary (params?: {}): Promise; - sapiGetBrokerRebateFuturesRecentRecord (params?: {}): Promise; - sapiGetBrokerSubAccountApiIpRestriction (params?: {}): Promise; - sapiGetBrokerUniversalTransfer (params?: {}): Promise; - sapiGetAccountApiRestrictions (params?: {}): Promise; - sapiGetC2cOrderMatchListUserOrderHistory (params?: {}): Promise; - sapiGetNftHistoryTransactions (params?: {}): Promise; - sapiGetNftHistoryDeposit (params?: {}): Promise; - sapiGetNftHistoryWithdraw (params?: {}): Promise; - sapiGetNftUserGetAsset (params?: {}): Promise; - sapiGetPayTransactions (params?: {}): Promise; - sapiGetGiftcardVerify (params?: {}): Promise; - sapiGetGiftcardCryptographyRsaPublicKey (params?: {}): Promise; - sapiGetGiftcardBuyCodeTokenLimit (params?: {}): Promise; - sapiGetAlgoSpotOpenOrders (params?: {}): Promise; - sapiGetAlgoSpotHistoricalOrders (params?: {}): Promise; - sapiGetAlgoSpotSubOrders (params?: {}): Promise; - sapiGetAlgoFuturesOpenOrders (params?: {}): Promise; - sapiGetAlgoFuturesHistoricalOrders (params?: {}): Promise; - sapiGetAlgoFuturesSubOrders (params?: {}): Promise; - sapiGetPortfolioAccount (params?: {}): Promise; - sapiGetPortfolioCollateralRate (params?: {}): Promise; - sapiGetPortfolioPmLoan (params?: {}): Promise; - sapiGetPortfolioInterestHistory (params?: {}): Promise; - sapiGetPortfolioAssetIndexPrice (params?: {}): Promise; - sapiGetPortfolioRepayFuturesSwitch (params?: {}): Promise; - sapiGetPortfolioMarginAssetLeverage (params?: {}): Promise; - sapiGetStakingProductList (params?: {}): Promise; - sapiGetStakingPosition (params?: {}): Promise; - sapiGetStakingStakingRecord (params?: {}): Promise; - sapiGetStakingPersonalLeftQuota (params?: {}): Promise; - sapiGetLendingAutoInvestTargetAssetList (params?: {}): Promise; - sapiGetLendingAutoInvestTargetAssetRoiList (params?: {}): Promise; - sapiGetLendingAutoInvestAllAsset (params?: {}): Promise; - sapiGetLendingAutoInvestSourceAssetList (params?: {}): Promise; - sapiGetLendingAutoInvestPlanList (params?: {}): Promise; - sapiGetLendingAutoInvestPlanId (params?: {}): Promise; - sapiGetLendingAutoInvestHistoryList (params?: {}): Promise; - sapiGetLendingAutoInvestIndexInfo (params?: {}): Promise; - sapiGetLendingAutoInvestIndexUserSummary (params?: {}): Promise; - sapiGetLendingAutoInvestOneOffStatus (params?: {}): Promise; - sapiGetLendingAutoInvestRedeemHistory (params?: {}): Promise; - sapiGetLendingAutoInvestRebalanceHistory (params?: {}): Promise; - sapiGetSimpleEarnFlexibleList (params?: {}): Promise; - sapiGetSimpleEarnLockedList (params?: {}): Promise; - sapiGetSimpleEarnFlexiblePersonalLeftQuota (params?: {}): Promise; - sapiGetSimpleEarnLockedPersonalLeftQuota (params?: {}): Promise; - sapiGetSimpleEarnFlexibleSubscriptionPreview (params?: {}): Promise; - sapiGetSimpleEarnLockedSubscriptionPreview (params?: {}): Promise; - sapiGetSimpleEarnFlexibleHistoryRateHistory (params?: {}): Promise; - sapiGetSimpleEarnFlexiblePosition (params?: {}): Promise; - sapiGetSimpleEarnLockedPosition (params?: {}): Promise; - sapiGetSimpleEarnAccount (params?: {}): Promise; - sapiGetSimpleEarnFlexibleHistorySubscriptionRecord (params?: {}): Promise; - sapiGetSimpleEarnLockedHistorySubscriptionRecord (params?: {}): Promise; - sapiGetSimpleEarnFlexibleHistoryRedemptionRecord (params?: {}): Promise; - sapiGetSimpleEarnLockedHistoryRedemptionRecord (params?: {}): Promise; - sapiGetSimpleEarnFlexibleHistoryRewardsRecord (params?: {}): Promise; - sapiGetSimpleEarnLockedHistoryRewardsRecord (params?: {}): Promise; - sapiGetSimpleEarnFlexibleHistoryCollateralRecord (params?: {}): Promise; - sapiPostAssetDust (params?: {}): Promise; - sapiPostAssetDustBtc (params?: {}): Promise; - sapiPostAssetTransfer (params?: {}): Promise; - sapiPostAssetGetFundingAsset (params?: {}): Promise; - sapiPostAssetConvertTransfer (params?: {}): Promise; - sapiPostAccountDisableFastWithdrawSwitch (params?: {}): Promise; - sapiPostAccountEnableFastWithdrawSwitch (params?: {}): Promise; - sapiPostCapitalWithdrawApply (params?: {}): Promise; - sapiPostCapitalContractConvertibleCoins (params?: {}): Promise; - sapiPostCapitalDepositCreditApply (params?: {}): Promise; - sapiPostMarginTransfer (params?: {}): Promise; - sapiPostMarginLoan (params?: {}): Promise; - sapiPostMarginRepay (params?: {}): Promise; - sapiPostMarginOrder (params?: {}): Promise; - sapiPostMarginOrderOco (params?: {}): Promise; - sapiPostMarginDust (params?: {}): Promise; - sapiPostMarginExchangeSmallLiability (params?: {}): Promise; - sapiPostMarginIsolatedTransfer (params?: {}): Promise; - sapiPostMarginIsolatedAccount (params?: {}): Promise; - sapiPostMarginMaxLeverage (params?: {}): Promise; - sapiPostBnbBurn (params?: {}): Promise; - sapiPostSubAccountVirtualSubAccount (params?: {}): Promise; - sapiPostSubAccountMarginTransfer (params?: {}): Promise; - sapiPostSubAccountMarginEnable (params?: {}): Promise; - sapiPostSubAccountFuturesEnable (params?: {}): Promise; - sapiPostSubAccountFuturesTransfer (params?: {}): Promise; - sapiPostSubAccountFuturesInternalTransfer (params?: {}): Promise; - sapiPostSubAccountTransferSubToSub (params?: {}): Promise; - sapiPostSubAccountTransferSubToMaster (params?: {}): Promise; - sapiPostSubAccountUniversalTransfer (params?: {}): Promise; - sapiPostSubAccountOptionsEnable (params?: {}): Promise; - sapiPostManagedSubaccountDeposit (params?: {}): Promise; - sapiPostManagedSubaccountWithdraw (params?: {}): Promise; - sapiPostUserDataStream (params?: {}): Promise; - sapiPostUserDataStreamIsolated (params?: {}): Promise; - sapiPostFuturesTransfer (params?: {}): Promise; - sapiPostLendingCustomizedFixedPurchase (params?: {}): Promise; - sapiPostLendingDailyPurchase (params?: {}): Promise; - sapiPostLendingDailyRedeem (params?: {}): Promise; - sapiPostBswapLiquidityAdd (params?: {}): Promise; - sapiPostBswapLiquidityRemove (params?: {}): Promise; - sapiPostBswapSwap (params?: {}): Promise; - sapiPostBswapClaimRewards (params?: {}): Promise; - sapiPostBlvtSubscribe (params?: {}): Promise; - sapiPostBlvtRedeem (params?: {}): Promise; - sapiPostApiReferralCustomization (params?: {}): Promise; - sapiPostApiReferralUserCustomization (params?: {}): Promise; - sapiPostApiReferralRebateHistoricalRecord (params?: {}): Promise; - sapiPostApiReferralKickbackHistoricalRecord (params?: {}): Promise; - sapiPostBrokerSubAccount (params?: {}): Promise; - sapiPostBrokerSubAccountMargin (params?: {}): Promise; - sapiPostBrokerSubAccountFutures (params?: {}): Promise; - sapiPostBrokerSubAccountApi (params?: {}): Promise; - sapiPostBrokerSubAccountApiPermission (params?: {}): Promise; - sapiPostBrokerSubAccountApiCommission (params?: {}): Promise; - sapiPostBrokerSubAccountApiCommissionFutures (params?: {}): Promise; - sapiPostBrokerSubAccountApiCommissionCoinFutures (params?: {}): Promise; - sapiPostBrokerTransfer (params?: {}): Promise; - sapiPostBrokerTransferFutures (params?: {}): Promise; - sapiPostBrokerRebateHistoricalRecord (params?: {}): Promise; - sapiPostBrokerSubAccountBnbBurnSpot (params?: {}): Promise; - sapiPostBrokerSubAccountBnbBurnMarginInterest (params?: {}): Promise; - sapiPostBrokerSubAccountBlvt (params?: {}): Promise; - sapiPostBrokerSubAccountApiIpRestriction (params?: {}): Promise; - sapiPostBrokerSubAccountApiIpRestrictionIpList (params?: {}): Promise; - sapiPostBrokerUniversalTransfer (params?: {}): Promise; - sapiPostBrokerSubAccountApiPermissionUniversalTransfer (params?: {}): Promise; - sapiPostBrokerSubAccountApiPermissionVanillaOptions (params?: {}): Promise; - sapiPostGiftcardCreateCode (params?: {}): Promise; - sapiPostGiftcardRedeemCode (params?: {}): Promise; - sapiPostGiftcardBuyCode (params?: {}): Promise; - sapiPostAlgoSpotNewOrderTwap (params?: {}): Promise; - sapiPostAlgoFuturesNewOrderVp (params?: {}): Promise; - sapiPostAlgoFuturesNewOrderTwap (params?: {}): Promise; - sapiPostStakingPurchase (params?: {}): Promise; - sapiPostStakingRedeem (params?: {}): Promise; - sapiPostStakingSetAutoStaking (params?: {}): Promise; - sapiPostPortfolioRepay (params?: {}): Promise; - sapiPostLoanVipRenew (params?: {}): Promise; - sapiPostLoanVipBorrow (params?: {}): Promise; - sapiPostLoanBorrow (params?: {}): Promise; - sapiPostLoanRepay (params?: {}): Promise; - sapiPostLoanAdjustLtv (params?: {}): Promise; - sapiPostLoanCustomizeMarginCall (params?: {}): Promise; - sapiPostLoanFlexibleBorrow (params?: {}): Promise; - sapiPostLoanFlexibleRepay (params?: {}): Promise; - sapiPostLoanFlexibleAdjustLtv (params?: {}): Promise; - sapiPostLoanVipRepay (params?: {}): Promise; - sapiPostConvertGetQuote (params?: {}): Promise; - sapiPostConvertAcceptQuote (params?: {}): Promise; - sapiPostPortfolioAutoCollection (params?: {}): Promise; - sapiPostPortfolioAssetCollection (params?: {}): Promise; - sapiPostPortfolioBnbTransfer (params?: {}): Promise; - sapiPostPortfolioRepayFuturesSwitch (params?: {}): Promise; - sapiPostPortfolioRepayFuturesNegativeBalance (params?: {}): Promise; - sapiPostLendingAutoInvestPlanAdd (params?: {}): Promise; - sapiPostLendingAutoInvestPlanEdit (params?: {}): Promise; - sapiPostLendingAutoInvestPlanEditStatus (params?: {}): Promise; - sapiPostLendingAutoInvestOneOff (params?: {}): Promise; - sapiPostLendingAutoInvestRedeem (params?: {}): Promise; - sapiPostSimpleEarnFlexibleSubscribe (params?: {}): Promise; - sapiPostSimpleEarnLockedSubscribe (params?: {}): Promise; - sapiPostSimpleEarnFlexibleRedeem (params?: {}): Promise; - sapiPostSimpleEarnLockedRedeem (params?: {}): Promise; - sapiPostSimpleEarnFlexibleSetAutoSubscribe (params?: {}): Promise; - sapiPostSimpleEarnLockedSetAutoSubscribe (params?: {}): Promise; - sapiPutUserDataStream (params?: {}): Promise; - sapiPutUserDataStreamIsolated (params?: {}): Promise; - sapiDeleteMarginOpenOrders (params?: {}): Promise; - sapiDeleteMarginOrder (params?: {}): Promise; - sapiDeleteMarginOrderList (params?: {}): Promise; - sapiDeleteMarginIsolatedAccount (params?: {}): Promise; - sapiDeleteUserDataStream (params?: {}): Promise; - sapiDeleteUserDataStreamIsolated (params?: {}): Promise; - sapiDeleteBrokerSubAccountApi (params?: {}): Promise; - sapiDeleteBrokerSubAccountApiIpRestrictionIpList (params?: {}): Promise; - sapiDeleteAlgoSpotOrder (params?: {}): Promise; - sapiDeleteAlgoFuturesOrder (params?: {}): Promise; - sapiDeleteSubAccountSubAccountApiIpRestrictionIpList (params?: {}): Promise; - sapiV2GetSubAccountFuturesAccount (params?: {}): Promise; - sapiV2GetSubAccountFuturesAccountSummary (params?: {}): Promise; - sapiV2GetSubAccountFuturesPositionRisk (params?: {}): Promise; - sapiV2PostSubAccountSubAccountApiIpRestriction (params?: {}): Promise; - sapiV3GetSubAccountAssets (params?: {}): Promise; - sapiV3PostAssetGetUserAsset (params?: {}): Promise; - sapiV4GetSubAccountAssets (params?: {}): Promise; - dapiPublicGetPing (params?: {}): Promise; - dapiPublicGetTime (params?: {}): Promise; - dapiPublicGetExchangeInfo (params?: {}): Promise; - dapiPublicGetDepth (params?: {}): Promise; - dapiPublicGetTrades (params?: {}): Promise; - dapiPublicGetHistoricalTrades (params?: {}): Promise; - dapiPublicGetAggTrades (params?: {}): Promise; - dapiPublicGetPremiumIndex (params?: {}): Promise; - dapiPublicGetFundingRate (params?: {}): Promise; - dapiPublicGetKlines (params?: {}): Promise; - dapiPublicGetContinuousKlines (params?: {}): Promise; - dapiPublicGetIndexPriceKlines (params?: {}): Promise; - dapiPublicGetMarkPriceKlines (params?: {}): Promise; - dapiPublicGetPremiumIndexKlines (params?: {}): Promise; - dapiPublicGetTicker24hr (params?: {}): Promise; - dapiPublicGetTickerPrice (params?: {}): Promise; - dapiPublicGetTickerBookTicker (params?: {}): Promise; - dapiPublicGetConstituents (params?: {}): Promise; - dapiPublicGetOpenInterest (params?: {}): Promise; - dapiDataGetDeliveryPrice (params?: {}): Promise; - dapiDataGetOpenInterestHist (params?: {}): Promise; - dapiDataGetTopLongShortAccountRatio (params?: {}): Promise; - dapiDataGetTopLongShortPositionRatio (params?: {}): Promise; - dapiDataGetGlobalLongShortAccountRatio (params?: {}): Promise; - dapiDataGetTakerBuySellVol (params?: {}): Promise; - dapiDataGetBasis (params?: {}): Promise; - dapiPrivateGetPositionSideDual (params?: {}): Promise; - dapiPrivateGetOrderAmendment (params?: {}): Promise; - dapiPrivateGetOrder (params?: {}): Promise; - dapiPrivateGetOpenOrder (params?: {}): Promise; - dapiPrivateGetOpenOrders (params?: {}): Promise; - dapiPrivateGetAllOrders (params?: {}): Promise; - dapiPrivateGetBalance (params?: {}): Promise; - dapiPrivateGetAccount (params?: {}): Promise; - dapiPrivateGetPositionMarginHistory (params?: {}): Promise; - dapiPrivateGetPositionRisk (params?: {}): Promise; - dapiPrivateGetUserTrades (params?: {}): Promise; - dapiPrivateGetIncome (params?: {}): Promise; - dapiPrivateGetLeverageBracket (params?: {}): Promise; - dapiPrivateGetForceOrders (params?: {}): Promise; - dapiPrivateGetAdlQuantile (params?: {}): Promise; - dapiPrivateGetCommissionRate (params?: {}): Promise; - dapiPrivateGetIncomeAsyn (params?: {}): Promise; - dapiPrivateGetIncomeAsynId (params?: {}): Promise; - dapiPrivateGetPmExchangeInfo (params?: {}): Promise; - dapiPrivateGetPmAccountInfo (params?: {}): Promise; - dapiPrivatePostPositionSideDual (params?: {}): Promise; - dapiPrivatePostOrder (params?: {}): Promise; - dapiPrivatePostBatchOrders (params?: {}): Promise; - dapiPrivatePostCountdownCancelAll (params?: {}): Promise; - dapiPrivatePostLeverage (params?: {}): Promise; - dapiPrivatePostMarginType (params?: {}): Promise; - dapiPrivatePostPositionMargin (params?: {}): Promise; - dapiPrivatePostListenKey (params?: {}): Promise; - dapiPrivatePutListenKey (params?: {}): Promise; - dapiPrivatePutOrder (params?: {}): Promise; - dapiPrivatePutBatchOrders (params?: {}): Promise; - dapiPrivateDeleteOrder (params?: {}): Promise; - dapiPrivateDeleteAllOpenOrders (params?: {}): Promise; - dapiPrivateDeleteBatchOrders (params?: {}): Promise; - dapiPrivateDeleteListenKey (params?: {}): Promise; - dapiPrivateV2GetLeverageBracket (params?: {}): Promise; - fapiPublicGetPing (params?: {}): Promise; - fapiPublicGetTime (params?: {}): Promise; - fapiPublicGetExchangeInfo (params?: {}): Promise; - fapiPublicGetDepth (params?: {}): Promise; - fapiPublicGetTrades (params?: {}): Promise; - fapiPublicGetHistoricalTrades (params?: {}): Promise; - fapiPublicGetAggTrades (params?: {}): Promise; - fapiPublicGetKlines (params?: {}): Promise; - fapiPublicGetContinuousKlines (params?: {}): Promise; - fapiPublicGetMarkPriceKlines (params?: {}): Promise; - fapiPublicGetIndexPriceKlines (params?: {}): Promise; - fapiPublicGetFundingRate (params?: {}): Promise; - fapiPublicGetFundingInfo (params?: {}): Promise; - fapiPublicGetPremiumIndex (params?: {}): Promise; - fapiPublicGetTicker24hr (params?: {}): Promise; - fapiPublicGetTickerPrice (params?: {}): Promise; - fapiPublicGetTickerBookTicker (params?: {}): Promise; - fapiPublicGetOpenInterest (params?: {}): Promise; - fapiPublicGetIndexInfo (params?: {}): Promise; - fapiPublicGetAssetIndex (params?: {}): Promise; - fapiPublicGetConstituents (params?: {}): Promise; - fapiPublicGetApiTradingStatus (params?: {}): Promise; - fapiPublicGetLvtKlines (params?: {}): Promise; - fapiDataGetDeliveryPrice (params?: {}): Promise; - fapiDataGetOpenInterestHist (params?: {}): Promise; - fapiDataGetTopLongShortAccountRatio (params?: {}): Promise; - fapiDataGetTopLongShortPositionRatio (params?: {}): Promise; - fapiDataGetGlobalLongShortAccountRatio (params?: {}): Promise; - fapiDataGetTakerlongshortRatio (params?: {}): Promise; - fapiDataGetBasis (params?: {}): Promise; - fapiPrivateGetForceOrders (params?: {}): Promise; - fapiPrivateGetAllOrders (params?: {}): Promise; - fapiPrivateGetOpenOrder (params?: {}): Promise; - fapiPrivateGetOpenOrders (params?: {}): Promise; - fapiPrivateGetOrder (params?: {}): Promise; - fapiPrivateGetAccount (params?: {}): Promise; - fapiPrivateGetBalance (params?: {}): Promise; - fapiPrivateGetLeverageBracket (params?: {}): Promise; - fapiPrivateGetPositionMarginHistory (params?: {}): Promise; - fapiPrivateGetPositionRisk (params?: {}): Promise; - fapiPrivateGetPositionSideDual (params?: {}): Promise; - fapiPrivateGetUserTrades (params?: {}): Promise; - fapiPrivateGetIncome (params?: {}): Promise; - fapiPrivateGetCommissionRate (params?: {}): Promise; - fapiPrivateGetApiTradingStatus (params?: {}): Promise; - fapiPrivateGetMultiAssetsMargin (params?: {}): Promise; - fapiPrivateGetApiReferralIfNewUser (params?: {}): Promise; - fapiPrivateGetApiReferralCustomization (params?: {}): Promise; - fapiPrivateGetApiReferralUserCustomization (params?: {}): Promise; - fapiPrivateGetApiReferralTraderNum (params?: {}): Promise; - fapiPrivateGetApiReferralOverview (params?: {}): Promise; - fapiPrivateGetApiReferralTradeVol (params?: {}): Promise; - fapiPrivateGetApiReferralRebateVol (params?: {}): Promise; - fapiPrivateGetApiReferralTraderSummary (params?: {}): Promise; - fapiPrivateGetAdlQuantile (params?: {}): Promise; - fapiPrivateGetPmAccountInfo (params?: {}): Promise; - fapiPrivateGetOrderAmendment (params?: {}): Promise; - fapiPrivateGetIncomeAsyn (params?: {}): Promise; - fapiPrivateGetIncomeAsynId (params?: {}): Promise; - fapiPrivateGetOrderAsyn (params?: {}): Promise; - fapiPrivateGetOrderAsynId (params?: {}): Promise; - fapiPrivateGetTradeAsyn (params?: {}): Promise; - fapiPrivateGetTradeAsynId (params?: {}): Promise; - fapiPrivatePostBatchOrders (params?: {}): Promise; - fapiPrivatePostPositionSideDual (params?: {}): Promise; - fapiPrivatePostPositionMargin (params?: {}): Promise; - fapiPrivatePostMarginType (params?: {}): Promise; - fapiPrivatePostOrder (params?: {}): Promise; - fapiPrivatePostLeverage (params?: {}): Promise; - fapiPrivatePostListenKey (params?: {}): Promise; - fapiPrivatePostCountdownCancelAll (params?: {}): Promise; - fapiPrivatePostMultiAssetsMargin (params?: {}): Promise; - fapiPrivatePostApiReferralCustomization (params?: {}): Promise; - fapiPrivatePostApiReferralUserCustomization (params?: {}): Promise; - fapiPrivatePutListenKey (params?: {}): Promise; - fapiPrivatePutOrder (params?: {}): Promise; - fapiPrivatePutBatchOrders (params?: {}): Promise; - fapiPrivateDeleteBatchOrders (params?: {}): Promise; - fapiPrivateDeleteOrder (params?: {}): Promise; - fapiPrivateDeleteAllOpenOrders (params?: {}): Promise; - fapiPrivateDeleteListenKey (params?: {}): Promise; - fapiPublicV2GetTickerPrice (params?: {}): Promise; - fapiPrivateV2GetAccount (params?: {}): Promise; - fapiPrivateV2GetBalance (params?: {}): Promise; - fapiPrivateV2GetPositionRisk (params?: {}): Promise; - eapiPublicGetPing (params?: {}): Promise; - eapiPublicGetTime (params?: {}): Promise; - eapiPublicGetExchangeInfo (params?: {}): Promise; - eapiPublicGetIndex (params?: {}): Promise; - eapiPublicGetTicker (params?: {}): Promise; - eapiPublicGetMark (params?: {}): Promise; - eapiPublicGetDepth (params?: {}): Promise; - eapiPublicGetKlines (params?: {}): Promise; - eapiPublicGetTrades (params?: {}): Promise; - eapiPublicGetHistoricalTrades (params?: {}): Promise; - eapiPublicGetExerciseHistory (params?: {}): Promise; - eapiPublicGetOpenInterest (params?: {}): Promise; - eapiPrivateGetAccount (params?: {}): Promise; - eapiPrivateGetPosition (params?: {}): Promise; - eapiPrivateGetOpenOrders (params?: {}): Promise; - eapiPrivateGetHistoryOrders (params?: {}): Promise; - eapiPrivateGetUserTrades (params?: {}): Promise; - eapiPrivateGetExerciseRecord (params?: {}): Promise; - eapiPrivateGetBill (params?: {}): Promise; - eapiPrivateGetIncomeAsyn (params?: {}): Promise; - eapiPrivateGetIncomeAsynId (params?: {}): Promise; - eapiPrivateGetMarginAccount (params?: {}): Promise; - eapiPrivateGetMmp (params?: {}): Promise; - eapiPrivateGetCountdownCancelAll (params?: {}): Promise; - eapiPrivateGetOrder (params?: {}): Promise; - eapiPrivatePostOrder (params?: {}): Promise; - eapiPrivatePostBatchOrders (params?: {}): Promise; - eapiPrivatePostListenKey (params?: {}): Promise; - eapiPrivatePostMmpSet (params?: {}): Promise; - eapiPrivatePostMmpReset (params?: {}): Promise; - eapiPrivatePostCountdownCancelAll (params?: {}): Promise; - eapiPrivatePostCountdownCancelAllHeartBeat (params?: {}): Promise; - eapiPrivatePutListenKey (params?: {}): Promise; - eapiPrivateDeleteOrder (params?: {}): Promise; - eapiPrivateDeleteBatchOrders (params?: {}): Promise; - eapiPrivateDeleteAllOpenOrders (params?: {}): Promise; - eapiPrivateDeleteAllOpenOrdersByUnderlying (params?: {}): Promise; - eapiPrivateDeleteListenKey (params?: {}): Promise; - publicGetPing (params?: {}): Promise; - publicGetTime (params?: {}): Promise; - publicGetDepth (params?: {}): Promise; - publicGetTrades (params?: {}): Promise; - publicGetAggTrades (params?: {}): Promise; - publicGetHistoricalTrades (params?: {}): Promise; - publicGetKlines (params?: {}): Promise; - publicGetUiKlines (params?: {}): Promise; - publicGetTicker24hr (params?: {}): Promise; - publicGetTicker (params?: {}): Promise; - publicGetTickerTradingDay (params?: {}): Promise; - publicGetTickerPrice (params?: {}): Promise; - publicGetTickerBookTicker (params?: {}): Promise; - publicGetExchangeInfo (params?: {}): Promise; - publicGetAvgPrice (params?: {}): Promise; - publicPutUserDataStream (params?: {}): Promise; - publicPostUserDataStream (params?: {}): Promise; - publicDeleteUserDataStream (params?: {}): Promise; - privateGetAllOrderList (params?: {}): Promise; - privateGetOpenOrderList (params?: {}): Promise; - privateGetOrderList (params?: {}): Promise; - privateGetOrder (params?: {}): Promise; - privateGetOpenOrders (params?: {}): Promise; - privateGetAllOrders (params?: {}): Promise; - privateGetAccount (params?: {}): Promise; - privateGetMyTrades (params?: {}): Promise; - privateGetRateLimitOrder (params?: {}): Promise; - privateGetMyPreventedMatches (params?: {}): Promise; - privateGetMyAllocations (params?: {}): Promise; - privateGetAccountCommission (params?: {}): Promise; - privatePostOrderOco (params?: {}): Promise; - privatePostSorOrder (params?: {}): Promise; - privatePostSorOrderTest (params?: {}): Promise; - privatePostOrder (params?: {}): Promise; - privatePostOrderCancelReplace (params?: {}): Promise; - privatePostOrderTest (params?: {}): Promise; - privateDeleteOpenOrders (params?: {}): Promise; - privateDeleteOrderList (params?: {}): Promise; - privateDeleteOrder (params?: {}): Promise; - papiGetUmOrder (params?: {}): Promise; - papiGetUmOpenOrder (params?: {}): Promise; - papiGetUmOpenOrders (params?: {}): Promise; - papiGetUmAllOrders (params?: {}): Promise; - papiGetCmOrder (params?: {}): Promise; - papiGetCmOpenOrder (params?: {}): Promise; - papiGetCmOpenOrders (params?: {}): Promise; - papiGetCmAllOrders (params?: {}): Promise; - papiGetUmConditionalOpenOrder (params?: {}): Promise; - papiGetUmConditionalOpenOrders (params?: {}): Promise; - papiGetUmConditionalOrderHistory (params?: {}): Promise; - papiGetUmConditionalAllOrders (params?: {}): Promise; - papiGetCmConditionalOpenOrder (params?: {}): Promise; - papiGetCmConditionalOpenOrders (params?: {}): Promise; - papiGetCmConditionalOrderHistory (params?: {}): Promise; - papiGetCmConditionalAllOrders (params?: {}): Promise; - papiGetMarginOrder (params?: {}): Promise; - papiGetMarginOpenOrders (params?: {}): Promise; - papiGetMarginAllOrders (params?: {}): Promise; - papiGetMarginOrderList (params?: {}): Promise; - papiGetMarginAllOrderList (params?: {}): Promise; - papiGetMarginOpenOrderList (params?: {}): Promise; - papiGetMarginMyTrades (params?: {}): Promise; - papiGetBalance (params?: {}): Promise; - papiGetAccount (params?: {}): Promise; - papiGetMarginMaxBorrowable (params?: {}): Promise; - papiGetMarginMaxWithdraw (params?: {}): Promise; - papiGetUmPositionRisk (params?: {}): Promise; - papiGetCmPositionRisk (params?: {}): Promise; - papiGetUmPositionSideDual (params?: {}): Promise; - papiGetCmPositionSideDual (params?: {}): Promise; - papiGetUmUserTrades (params?: {}): Promise; - papiGetCmUserTrades (params?: {}): Promise; - papiGetUmLeverageBracket (params?: {}): Promise; - papiGetCmLeverageBracket (params?: {}): Promise; - papiGetMarginForceOrders (params?: {}): Promise; - papiGetUmForceOrders (params?: {}): Promise; - papiGetCmForceOrders (params?: {}): Promise; - papiGetUmApiTradingStatus (params?: {}): Promise; - papiGetUmCommissionRate (params?: {}): Promise; - papiGetCmCommissionRate (params?: {}): Promise; - papiGetMarginMarginLoan (params?: {}): Promise; - papiGetMarginRepayLoan (params?: {}): Promise; - papiGetMarginMarginInterestHistory (params?: {}): Promise; - papiGetPortfolioInterestHistory (params?: {}): Promise; - papiGetUmIncome (params?: {}): Promise; - papiGetCmIncome (params?: {}): Promise; - papiGetUmAccount (params?: {}): Promise; - papiGetCmAccount (params?: {}): Promise; - papiGetRepayFuturesSwitch (params?: {}): Promise; - papiGetUmAdlQuantile (params?: {}): Promise; - papiGetCmAdlQuantile (params?: {}): Promise; - papiPostUmOrder (params?: {}): Promise; - papiPostUmConditionalOrder (params?: {}): Promise; - papiPostCmOrder (params?: {}): Promise; - papiPostCmConditionalOrder (params?: {}): Promise; - papiPostMarginOrder (params?: {}): Promise; - papiPostMarginLoan (params?: {}): Promise; - papiPostRepayLoan (params?: {}): Promise; - papiPostMarginOrderOco (params?: {}): Promise; - papiPostUmLeverage (params?: {}): Promise; - papiPostCmLeverage (params?: {}): Promise; - papiPostUmPositionSideDual (params?: {}): Promise; - papiPostCmPositionSideDual (params?: {}): Promise; - papiPostAutoCollection (params?: {}): Promise; - papiPostBnbTransfer (params?: {}): Promise; - papiPostRepayFuturesSwitch (params?: {}): Promise; - papiPostRepayFuturesNegativeBalance (params?: {}): Promise; - papiPostListenKey (params?: {}): Promise; - papiPostAssetCollection (params?: {}): Promise; - papiPutListenKey (params?: {}): Promise; - papiDeleteUmOrder (params?: {}): Promise; - papiDeleteUmConditionalOrder (params?: {}): Promise; - papiDeleteUmAllOpenOrders (params?: {}): Promise; - papiDeleteUmConditionalAllOpenOrders (params?: {}): Promise; - papiDeleteCmOrder (params?: {}): Promise; - papiDeleteCmConditionalOrder (params?: {}): Promise; - papiDeleteCmAllOpenOrders (params?: {}): Promise; - papiDeleteCmConditionalAllOpenOrders (params?: {}): Promise; - papiDeleteMarginOrder (params?: {}): Promise; - papiDeleteMarginAllOpenOrders (params?: {}): Promise; - papiDeleteMarginOrderList (params?: {}): Promise; - papiDeleteListenKey (params?: {}): Promise; + v4PublicGetPing (params?: {}): Promise; + v4PublicGetStatus (params?: {}): Promise; + v4PublicGetTime (params?: {}): Promise; + v4PublicGetCurrencies (params?: {}): Promise; + v4PublicGetMarkets (params?: {}): Promise; + v4PublicGetTicker (params?: {}): Promise; + v4PublicGetTrades (params?: {}): Promise; + v4PublicGetOrderbook (params?: {}): Promise; + v4PublicGetCharts (params?: {}): Promise; + v4PublicGetChartsPair (params?: {}): Promise; + v4PrivateGetTransactions (params?: {}): Promise; + v4PrivateGetBalances (params?: {}): Promise; + v4PrivateGetKeys (params?: {}): Promise; + v4PrivateGetSessions (params?: {}): Promise; + v4PrivateGetProfile (params?: {}): Promise; + v4PrivatePostKeys (params?: {}): Promise; + v4PrivatePostOrders (params?: {}): Promise; + v4PrivateDeleteKeysId (params?: {}): Promise; } abstract class Exchange extends _Exchange {} diff --git a/ts/src/youngplatform.ts b/ts/src/youngplatform.ts index 707740abbe0a4..348e61c068cf8 100644 --- a/ts/src/youngplatform.ts +++ b/ts/src/youngplatform.ts @@ -2,14 +2,10 @@ // --------------------------------------------------------------------------- import Exchange from './abstract/youngplatform.js'; -import { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable, OnMaintenance, BadResponse, RequestTimeout, OrderNotFillable, MarginModeAlreadySet } from './base/errors.js'; +import { ExchangeError, InvalidOrder, AuthenticationError, PermissionDenied, BadRequest } from './base/errors.js'; import { Precise } from './base/Precise.js'; -import type { Int, OrderSide, Balances, OrderType, Trade, OHLCV, Order, FundingRateHistory, OpenInterest, Liquidation, OrderRequest, Str, Transaction, Ticker, OrderBook, Tickers, Market, Greeks, Strings, Currency, MarketInterface } from './base/types.js'; -import { TRUNCATE, DECIMAL_PLACES } from './base/functions/number.js'; -import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; -import { rsa } from './base/functions/rsa.js'; -import { eddsa } from './base/functions/crypto.js'; -import { ed25519 } from './static_dependencies/noble-curves/ed25519.js'; +import type { Int, Balances, Trade, Ticker, OrderBook, Market } from './base/types.js'; +import { DECIMAL_PLACES } from './base/functions/number.js'; // --------------------------------------------------------------------------- @@ -22,9 +18,9 @@ export default class youngplatform extends Exchange { return this.deepExtend (super.describe (), { 'id': 'youngplatform', 'name': 'Young Platform', - 'countries': [ 'JP', 'MT' ], // Japan, Malta + 'countries': [ 'IT', 'FR' ], // Japan, Malta 'rateLimit': 50, - 'certified': true, + 'certified': false, 'pro': true, // new metainfo2 interface 'has': { @@ -32,120 +28,114 @@ export default class youngplatform extends Exchange { 'spot': true, 'margin': true, 'swap': true, - 'future': true, - 'option': true, - 'addMargin': true, - 'borrowCrossMargin': true, - 'borrowIsolatedMargin': true, - 'cancelAllOrders': true, + 'future': false, + 'option': false, + 'addMargin': false, + 'borrowCrossMargin': false, + 'borrowIsolatedMargin': false, + 'cancelAllOrders': false, 'cancelOrder': true, - 'cancelOrders': true, // contract only + 'cancelOrders': false, // contract only 'closeAllPositions': false, 'closePosition': false, 'createDepositAddress': false, 'createOrder': true, - 'createOrders': true, - 'createPostOnlyOrder': true, - 'createReduceOnlyOrder': true, + 'createOrders': false, + 'createPostOnlyOrder': false, + 'createReduceOnlyOrder': false, 'createStopLimitOrder': true, - 'createStopMarketOrder': false, + 'createStopMarketOrder': true, 'createStopOrder': true, - 'editOrder': true, + 'editOrder': false, 'fetchAccounts': undefined, 'fetchBalance': true, 'fetchBidsAsks': true, - 'fetchBorrowInterest': true, + 'fetchBorrowInterest': false, 'fetchBorrowRateHistories': false, - 'fetchBorrowRateHistory': true, - 'fetchCanceledOrders': 'emulated', - 'fetchClosedOrder': false, + 'fetchBorrowRateHistory': false, + 'fetchCanceledOrders': true, + 'fetchClosedOrder': true, 'fetchClosedOrders': 'emulated', - 'fetchCrossBorrowRate': true, + 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, - 'fetchDeposit': false, + 'fetchDeposit': true, 'fetchDepositAddress': true, - 'fetchDepositAddresses': false, - 'fetchDepositAddressesByNetwork': false, + 'fetchDepositAddresses': true, + 'fetchDepositAddressesByNetwork': true, 'fetchDeposits': true, - 'fetchDepositsWithdrawals': false, + 'fetchDepositsWithdrawals': true, 'fetchDepositWithdrawFee': 'emulated', - 'fetchDepositWithdrawFees': true, - 'fetchFundingHistory': true, - 'fetchFundingRate': true, - 'fetchFundingRateHistory': true, - 'fetchFundingRates': true, - 'fetchGreeks': true, - 'fetchIndexOHLCV': true, + 'fetchDepositWithdrawFees': false, + 'fetchFundingHistory': false, + 'fetchFundingRate': false, + 'fetchFundingRateHistory': false, + 'fetchFundingRates': false, + 'fetchGreeks': false, + 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchL3OrderBook': false, 'fetchLedger': true, 'fetchLeverage': false, - 'fetchLeverageTiers': true, + 'fetchLeverageTiers': false, 'fetchLiquidations': false, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, - 'fetchMarkOHLCV': true, - 'fetchMyLiquidations': true, - 'fetchMySettlementHistory': true, + 'fetchMarkOHLCV': false, + 'fetchMyLiquidations': false, + 'fetchMySettlementHistory': false, 'fetchMyTrades': true, 'fetchOHLCV': true, - 'fetchOpenInterest': true, - 'fetchOpenInterestHistory': true, - 'fetchOpenOrder': false, + 'fetchOpenInterest': false, + 'fetchOpenInterestHistory': false, + 'fetchOpenOrder': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderBooks': false, 'fetchOrders': true, 'fetchOrderTrades': true, - 'fetchPosition': true, - 'fetchPositions': true, - 'fetchPositionsRisk': true, + 'fetchPosition': false, + 'fetchPositions': false, + 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, - 'fetchSettlementHistory': true, + 'fetchSettlementHistory': false, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, - 'fetchTradingFee': true, - 'fetchTradingFees': true, + 'fetchTradingFee': false, + 'fetchTradingFees': false, 'fetchTradingLimits': undefined, 'fetchTransactionFee': undefined, - 'fetchTransactionFees': true, - 'fetchTransactions': false, - 'fetchTransfers': true, + 'fetchTransactionFees': false, + 'fetchTransactions': true, + 'fetchTransfers': false, 'fetchUnderlyingAssets': false, 'fetchVolatilityHistory': false, 'fetchWithdrawAddresses': false, 'fetchWithdrawal': false, 'fetchWithdrawals': true, 'fetchWithdrawalWhitelist': false, - 'reduceMargin': true, - 'repayCrossMargin': true, - 'repayIsolatedMargin': true, - 'setLeverage': true, + 'reduceMargin': false, + 'repayCrossMargin': false, + 'repayIsolatedMargin': false, + 'setLeverage': false, 'setMargin': false, - 'setMarginMode': true, - 'setPositionMode': true, + 'setMarginMode': false, + 'setPositionMode': false, 'signIn': false, - 'transfer': true, + 'transfer': false, 'withdraw': true, }, 'timeframes': { - '1s': '1s', // spot only for now '1m': '1m', - '3m': '3m', '5m': '5m', '15m': '15m', - '30m': '30m', '1h': '1h', - '2h': '2h', '4h': '4h', - '6h': '6h', - '8h': '8h', '12h': '12h', '1d': '1d', '3d': '3d', @@ -155,864 +145,53 @@ export default class youngplatform extends Exchange { 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg', 'test': { - 'dapiPublic': 'https://testnet.binancefuture.com/dapi/v1', - 'dapiPrivate': 'https://testnet.binancefuture.com/dapi/v1', - 'dapiPrivateV2': 'https://testnet.binancefuture.com/dapi/v2', - 'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1', - 'fapiPublicV2': 'https://testnet.binancefuture.com/fapi/v2', - 'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1', - 'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2', - 'public': 'https://testnet.binance.vision/api/v3', - 'private': 'https://testnet.binance.vision/api/v3', - 'v1': 'https://testnet.binance.vision/api/v1', + 'rest': 'https://testbff.youngplatform.com/api/v4', }, 'api': { - 'sapi': 'https://api.binance.com/sapi/v1', - 'sapiV2': 'https://api.binance.com/sapi/v2', - 'sapiV3': 'https://api.binance.com/sapi/v3', - 'sapiV4': 'https://api.binance.com/sapi/v4', - 'dapiPublic': 'https://dapi.binance.com/dapi/v1', - 'dapiPrivate': 'https://dapi.binance.com/dapi/v1', - 'eapiPublic': 'https://eapi.binance.com/eapi/v1', - 'eapiPrivate': 'https://eapi.binance.com/eapi/v1', - 'dapiPrivateV2': 'https://dapi.binance.com/dapi/v2', - 'dapiData': 'https://dapi.binance.com/futures/data', - 'fapiPublic': 'https://fapi.binance.com/fapi/v1', - 'fapiPublicV2': 'https://fapi.binance.com/fapi/v2', - 'fapiPrivate': 'https://fapi.binance.com/fapi/v1', - 'fapiData': 'https://fapi.binance.com/futures/data', - 'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2', - 'public': 'https://api.binance.com/api/v3', - 'private': 'https://api.binance.com/api/v3', - 'v1': 'https://api.binance.com/api/v1', - 'papi': 'https://papi.binance.com/papi/v1', + 'rest': 'https://bff.youngplatform.com/api/v4', }, - 'www': 'https://www.binance.com', + 'www': 'https://youngplatform.com/', 'referral': { - 'url': 'https://accounts.binance.com/en/register?ref=D7YA7CLY', + 'url': 'https://exchange.youngplatform.com/signup/?utm_source=website&utm_medium=menu&utm_campaign=homepageDesktop&ref=1311738', 'discount': 0.1, }, 'doc': [ - 'https://binance-docs.github.io/apidocs/spot/en', + 'https://youngplatform.stoplight.io/docs/bff/5jyiu57dlv9e7-authentication', ], - 'api_management': 'https://www.binance.com/en/usercenter/settings/api-management', - 'fees': 'https://www.binance.com/en/fee/schedule', + 'api_management': 'https://youngplatform.stoplight.io/docs/bff/5jyiu57dlv9e7-authentication', + 'fees': 'https://exchange.youngplatform.com/fees', }, 'api': { - // the API structure below will need 3-layer apidefs - 'sapi': { - // IP (sapi) request rate limit of 12 000 per minute - // 1 IP (sapi) => cost = 0.1 => (1000 / (50 * 0.1)) * 60 = 12000 - // 10 IP (sapi) => cost = 1 - // UID (sapi) request rate limit of 180 000 per minute - // 1 UID (sapi) => cost = 0.006667 => (1000 / (50 * 0.006667)) * 60 = 180000 - 'get': { - 'system/status': 0.1, - // these endpoints require this.apiKey - 'accountSnapshot': 240, // Weight(IP): 2400 => cost = 0.1 * 2400 = 240 - 'margin/asset': 1, // Weight(IP): 10 => cost = 0.1 * 10 = 1 - 'margin/pair': 1, - 'margin/allAssets': 0.1, - 'margin/allPairs': 0.1, - 'margin/priceIndex': 1, - // these endpoints require this.apiKey + this.secret - 'asset/assetDividend': 1, - 'asset/dribblet': 0.1, - 'asset/transfer': 0.1, - 'asset/assetDetail': 0.1, - 'asset/tradeFee': 0.1, - 'asset/ledger-transfer/cloud-mining/queryByPage': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 - 'asset/convert-transfer/queryByPage': 0.033335, - 'asset/wallet/balance': 6, // Weight(IP): 60 => cost = 0.1 * 60 = 6 - 'asset/custody/transfer-history': 6, // Weight(IP): 60 => cost = 0.1 * 60 = 6 - 'margin/loan': 1, - 'margin/repay': 1, - 'margin/account': 1, - 'margin/transfer': 0.1, - 'margin/interestHistory': 0.1, - 'margin/forceLiquidationRec': 0.1, - 'margin/order': 1, - 'margin/openOrders': 1, - 'margin/allOrders': 20, // Weight(IP): 200 => cost = 0.1 * 200 = 20 - 'margin/myTrades': 1, - 'margin/maxBorrowable': 5, // Weight(IP): 50 => cost = 0.1 * 50 = 5 - 'margin/maxTransferable': 5, - 'margin/tradeCoeff': 1, - 'margin/isolated/transfer': 0.1, - 'margin/isolated/account': 1, - 'margin/isolated/pair': 1, - 'margin/isolated/allPairs': 1, - 'margin/isolated/accountLimit': 0.1, - 'margin/interestRateHistory': 0.1, - 'margin/orderList': 1, - 'margin/allOrderList': 20, // Weight(IP): 200 => cost = 0.1 * 200 = 20 - 'margin/openOrderList': 1, - 'margin/crossMarginData': { 'cost': 0.1, 'noCoin': 0.5 }, - 'margin/isolatedMarginData': { 'cost': 0.1, 'noCoin': 1 }, - 'margin/isolatedMarginTier': 0.1, - 'margin/rateLimit/order': 2, - 'margin/dribblet': 0.1, - 'margin/dust': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20 - 'margin/crossMarginCollateralRatio': 10, - 'margin/exchange-small-liability': 0.6667, - 'margin/exchange-small-liability-history': 0.6667, - 'margin/next-hourly-interest-rate': 0.6667, - 'margin/capital-flow': 10, // Weight(IP): 100 => cost = 0.1 * 100 = 10 - 'margin/delist-schedule': 10, // Weight(IP): 100 => cost = 0.1 * 100 = 10 - 'margin/available-inventory': 0.3334, // Weight(UID): 50 => cost = 0.006667 * 50 = 0.3334 - 'margin/leverageBracket': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'loan/vip/loanable/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/vip/collateral/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/vip/request/data': 2.6668, // Weight(UID): 400 => cost = 0.006667 * 400 = 2.6668 - 'loan/vip/request/interestRate': 2.6668, // Weight(UID): 400 => cost = 0.006667 * 400 = 2.6668 - 'loan/income': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 - 'loan/ongoing/orders': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/ltv/adjustment/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/borrow/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/repay/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/loanable/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/collateral/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/repay/collateral/rate': 600, // Weight(IP): 6000 => cost = 0.1 * 6000 = 600 - 'loan/flexible/ongoing/orders': 30, // Weight(IP): 300 => cost = 0.1 * 300 = 30 - 'loan/flexible/borrow/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/flexible/repay/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/flexible/ltv/adjustment/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/flexible/loanable/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/flexible/collateral/data': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/vip/ongoing/orders': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/vip/repay/history': 40, // Weight(IP): 400 => cost = 0.1 * 400 = 40 - 'loan/vip/collateral/account': 600, // Weight(IP): 6000 => cost = 0.1 * 6000 = 600 - 'fiat/orders': 600.03, // Weight(UID): 90000 => cost = 0.006667 * 90000 = 600.03 - 'fiat/payments': 0.1, - 'futures/transfer': 1, - 'futures/histDataLink': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'rebate/taxQuery': 80.004, // Weight(UID): 12000 => cost = 0.006667 * 12000 = 80.004 - // https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi - 'capital/config/getall': 1, // get networks for withdrawing USDT ERC20 vs USDT Omni - 'capital/deposit/address': 1, - 'capital/deposit/address/list': 1, - 'capital/deposit/hisrec': 0.1, - 'capital/deposit/subAddress': 0.1, - 'capital/deposit/subHisrec': 0.1, - 'capital/withdraw/history': 1800, // Weight(IP): 18000 => cost = 0.1 * 18000 = 1800 - 'capital/contract/convertible-coins': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 - 'convert/tradeFlow': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'convert/exchangeInfo': 50, - 'convert/assetInfo': 10, - 'convert/orderStatus': 0.6667, - 'account/status': 0.1, - 'account/apiTradingStatus': 0.1, - 'account/apiRestrictions/ipRestriction': 0.1, - 'bnbBurn': 0.1, - 'sub-account/futures/account': 1, - 'sub-account/futures/accountSummary': 0.1, - 'sub-account/futures/positionRisk': 1, - 'sub-account/futures/internalTransfer': 0.1, - 'sub-account/list': 0.1, - 'sub-account/margin/account': 1, - 'sub-account/margin/accountSummary': 1, - 'sub-account/spotSummary': 0.1, - 'sub-account/status': 1, - 'sub-account/sub/transfer/history': 0.1, - 'sub-account/transfer/subUserHistory': 0.1, - 'sub-account/universalTransfer': 0.1, - 'sub-account/apiRestrictions/ipRestriction/thirdPartyList': 1, - 'sub-account/transaction-statistics': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 - 'sub-account/subAccountApi/ipRestriction': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'managed-subaccount/asset': 0.1, - 'managed-subaccount/accountSnapshot': 240, - 'managed-subaccount/queryTransLogForInvestor': 0.1, - 'managed-subaccount/queryTransLogForTradeParent': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 - 'managed-subaccount/fetch-future-asset': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 - 'managed-subaccount/marginAsset': 0.1, - 'managed-subaccount/info': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 - 'managed-subaccount/deposit/address': 0.006667, // Weight(UID): 1 => cost = 0.006667 * 1 = 0.006667 - 'managed-subaccount/query-trans-log': 0.40002, - // lending endpoints - 'lending/daily/product/list': 0.1, - 'lending/daily/userLeftQuota': 0.1, - 'lending/daily/userRedemptionQuota': 0.1, - 'lending/daily/token/position': 0.1, - 'lending/union/account': 0.1, - 'lending/union/purchaseRecord': 0.1, - 'lending/union/redemptionRecord': 0.1, - 'lending/union/interestHistory': 0.1, - 'lending/project/list': 0.1, - 'lending/project/position/list': 0.1, - // mining endpoints - 'mining/pub/algoList': 0.1, - 'mining/pub/coinList': 0.1, - 'mining/worker/detail': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5 - 'mining/worker/list': 0.5, - 'mining/payment/list': 0.5, - 'mining/statistics/user/status': 0.5, - 'mining/statistics/user/list': 0.5, - 'mining/payment/uid': 0.5, - // liquid swap endpoints - 'bswap/pools': 0.1, - 'bswap/liquidity': { 'cost': 0.1, 'noPoolId': 1 }, - 'bswap/liquidityOps': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'bswap/quote': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 - 'bswap/swap': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'bswap/poolConfigure': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 - 'bswap/addLiquidityPreview': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 - 'bswap/removeLiquidityPreview': 1.00005, // Weight(UID): 150 => cost = 0.006667 * 150 = 1.00005 - 'bswap/unclaimedRewards': 6.667, // Weight(UID): 1000 => cost = 0.006667 * 1000 = 6.667 - 'bswap/claimedHistory': 6.667, // Weight(UID): 1000 => cost = 0.006667 * 1000 = 6.667 - // leveraged token endpoints - 'blvt/tokenInfo': 0.1, - 'blvt/subscribe/record': 0.1, - 'blvt/redeem/record': 0.1, - 'blvt/userLimit': 0.1, - // broker api TODO (NOT IN DOCS) - 'apiReferral/ifNewUser': 1, - 'apiReferral/customization': 1, - 'apiReferral/userCustomization': 1, - 'apiReferral/rebate/recentRecord': 1, - 'apiReferral/rebate/historicalRecord': 1, - 'apiReferral/kickback/recentRecord': 1, - 'apiReferral/kickback/historicalRecord': 1, - // brokerage API TODO https://binance-docs.github.io/Brokerage-API/General/ does not state ratelimits - 'broker/subAccountApi': 1, - 'broker/subAccount': 1, - 'broker/subAccountApi/commission/futures': 1, - 'broker/subAccountApi/commission/coinFutures': 1, - 'broker/info': 1, - 'broker/transfer': 1, - 'broker/transfer/futures': 1, - 'broker/rebate/recentRecord': 1, - 'broker/rebate/historicalRecord': 1, - 'broker/subAccount/bnbBurn/status': 1, - 'broker/subAccount/depositHist': 1, - 'broker/subAccount/spotSummary': 1, - 'broker/subAccount/marginSummary': 1, - 'broker/subAccount/futuresSummary': 1, - 'broker/rebate/futures/recentRecord': 1, - 'broker/subAccountApi/ipRestriction': 1, - 'broker/universalTransfer': 1, - // v2 not supported yet - // GET /sapi/v2/broker/subAccount/futuresSummary - 'account/apiRestrictions': 0.1, - // c2c / p2p - 'c2c/orderMatch/listUserOrderHistory': 0.1, - // nft endpoints - 'nft/history/transactions': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'nft/history/deposit': 20.001, - 'nft/history/withdraw': 20.001, - 'nft/user/getAsset': 20.001, - 'pay/transactions': 20.001, - 'giftcard/verify': 0.1, - 'giftcard/cryptography/rsa-public-key': 0.1, - 'giftcard/buyCode/token-limit': 0.1, - 'algo/spot/openOrders': 0.1, - 'algo/spot/historicalOrders': 0.1, - 'algo/spot/subOrders': 0.1, - 'algo/futures/openOrders': 0.1, - 'algo/futures/historicalOrders': 0.1, - 'algo/futures/subOrders': 0.1, - 'portfolio/account': 0.1, - 'portfolio/collateralRate': 5, - 'portfolio/pmLoan': 3.3335, - 'portfolio/interest-history': 0.6667, - 'portfolio/asset-index-price': 0.1, - 'portfolio/repay-futures-switch': 3, // Weight(IP): 30 => cost = 0.1 * 30 = 3 - 'portfolio/margin-asset-leverage': 5, // Weight(IP): 50 => cost = 0.1 * 50 = 5 - // staking - 'staking/productList': 0.1, - 'staking/position': 0.1, - 'staking/stakingRecord': 0.1, - 'staking/personalLeftQuota': 0.1, - 'lending/auto-invest/target-asset/list': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/target-asset/roi/list': 0.1, - 'lending/auto-invest/all/asset': 0.1, - 'lending/auto-invest/source-asset/list': 0.1, - 'lending/auto-invest/plan/list': 0.1, - 'lending/auto-invest/plan/id': 0.1, - 'lending/auto-invest/history/list': 0.1, - 'lending/auto-invest/index/info': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/index/user-summary': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/one-off/status': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/redeem/history': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/rebalance/history': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - // simple earn - 'simple-earn/flexible/list': 15, - 'simple-earn/locked/list': 15, - 'simple-earn/flexible/personalLeftQuota': 15, - 'simple-earn/locked/personalLeftQuota': 15, - 'simple-earn/flexible/subscriptionPreview': 15, - 'simple-earn/locked/subscriptionPreview': 15, - 'simple-earn/flexible/history/rateHistory': 15, - 'simple-earn/flexible/position': 15, - 'simple-earn/locked/position': 15, - 'simple-earn/account': 15, - 'simple-earn/flexible/history/subscriptionRecord': 15, - 'simple-earn/locked/history/subscriptionRecord': 15, - 'simple-earn/flexible/history/redemptionRecord': 15, - 'simple-earn/locked/history/redemptionRecord': 15, - 'simple-earn/flexible/history/rewardsRecord': 15, - 'simple-earn/locked/history/rewardsRecord': 15, - 'simple-earn/flexible/history/collateralRecord': 0.1, - }, - 'post': { - 'asset/dust': 0.06667, // Weight(UID): 10 => cost = 0.006667 * 10 = 0.06667 - 'asset/dust-btc': 0.1, - 'asset/transfer': 6.0003, // Weight(UID): 900 => cost = 0.006667 * 900 = 6.0003 - 'asset/get-funding-asset': 0.1, - 'asset/convert-transfer': 0.033335, - 'account/disableFastWithdrawSwitch': 0.1, - 'account/enableFastWithdrawSwitch': 0.1, - // 'account/apiRestrictions/ipRestriction': 1, discontinued - // 'account/apiRestrictions/ipRestriction/ipList': 1, discontinued - 'capital/withdraw/apply': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 - 'capital/contract/convertible-coins': 4.0002, - 'capital/deposit/credit-apply': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'margin/transfer': 4.0002, - 'margin/loan': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'margin/repay': 20.001, - 'margin/order': 0.040002, // Weight(UID): 6 => cost = 0.006667 * 6 = 0.040002 - 'margin/order/oco': 0.040002, - 'margin/dust': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - 'margin/exchange-small-liability': 20.001, - // 'margin/isolated/create': 1, discontinued - 'margin/isolated/transfer': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 - 'margin/isolated/account': 2.0001, // Weight(UID): 300 => cost = 0.006667 * 300 = 2.0001 - 'margin/max-leverage': 300, // Weight(IP): 3000 => cost = 0.1 * 3000 = 300 - 'bnbBurn': 0.1, - 'sub-account/virtualSubAccount': 0.1, - 'sub-account/margin/transfer': 4.0002, // Weight(UID): 600 => cost = 0.006667 * 600 = 4.0002 - 'sub-account/margin/enable': 0.1, - 'sub-account/futures/enable': 0.1, - 'sub-account/futures/transfer': 0.1, - 'sub-account/futures/internalTransfer': 0.1, - 'sub-account/transfer/subToSub': 0.1, - 'sub-account/transfer/subToMaster': 0.1, - 'sub-account/universalTransfer': 0.1, - 'sub-account/options/enable': 0.1, - 'managed-subaccount/deposit': 0.1, - 'managed-subaccount/withdraw': 0.1, - 'userDataStream': 0.1, - 'userDataStream/isolated': 0.1, - 'futures/transfer': 0.1, - // lending - 'lending/customizedFixed/purchase': 0.1, - 'lending/daily/purchase': 0.1, - 'lending/daily/redeem': 0.1, - // liquid swap endpoints - 'bswap/liquidityAdd': 60, // Weight(UID): 1000 + (Additional: 1 request every 3 seconds = 0.333 requests per second) => cost = ( 1000 / rateLimit ) / 0.333 = 60.0000006 - 'bswap/liquidityRemove': 60, // Weight(UID): 1000 + (Additional: 1 request every three seconds) - 'bswap/swap': 60, // Weight(UID): 1000 + (Additional: 1 request every three seconds) - 'bswap/claimRewards': 6.667, // Weight(UID): 1000 => cost = 0.006667 * 1000 = 6.667 - // leveraged token endpoints - 'blvt/subscribe': 0.1, - 'blvt/redeem': 0.1, - // brokerage API TODO: NO MENTION OF RATELIMITS IN BROKERAGE DOCS - 'apiReferral/customization': 1, - 'apiReferral/userCustomization': 1, - 'apiReferral/rebate/historicalRecord': 1, - 'apiReferral/kickback/historicalRecord': 1, - 'broker/subAccount': 1, - 'broker/subAccount/margin': 1, - 'broker/subAccount/futures': 1, - 'broker/subAccountApi': 1, - 'broker/subAccountApi/permission': 1, - 'broker/subAccountApi/commission': 1, - 'broker/subAccountApi/commission/futures': 1, - 'broker/subAccountApi/commission/coinFutures': 1, - 'broker/transfer': 1, - 'broker/transfer/futures': 1, - 'broker/rebate/historicalRecord': 1, - 'broker/subAccount/bnbBurn/spot': 1, - 'broker/subAccount/bnbBurn/marginInterest': 1, - 'broker/subAccount/blvt': 1, - 'broker/subAccountApi/ipRestriction': 1, - 'broker/subAccountApi/ipRestriction/ipList': 1, - 'broker/universalTransfer': 1, - 'broker/subAccountApi/permission/universalTransfer': 1, - 'broker/subAccountApi/permission/vanillaOptions': 1, - // - 'giftcard/createCode': 0.1, - 'giftcard/redeemCode': 0.1, - 'giftcard/buyCode': 0.1, - 'algo/spot/newOrderTwap': 20.001, - 'algo/futures/newOrderVp': 20.001, - 'algo/futures/newOrderTwap': 20.001, - // staking - 'staking/purchase': 0.1, - 'staking/redeem': 0.1, - 'staking/setAutoStaking': 0.1, - 'portfolio/repay': 20.001, - 'loan/vip/renew': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 - 'loan/vip/borrow': 40.002, - 'loan/borrow': 40.002, - 'loan/repay': 40.002, - 'loan/adjust/ltv': 40.002, - 'loan/customize/margin_call': 40.002, - 'loan/flexible/borrow': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 - 'loan/flexible/repay': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 - 'loan/flexible/adjust/ltv': 40.002, // Weight(UID): 6000 => cost = 0.006667 * 6000 = 40.002 - 'loan/vip/repay': 40.002, - 'convert/getQuote': 1.3334, // Weight(UID): 200 => cost = 0.006667 * 200 = 1.3334 - 'convert/acceptQuote': 3.3335, // Weight(UID): 500 => cost = 0.006667 * 500 = 3.3335 - 'portfolio/auto-collection': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 - 'portfolio/asset-collection': 6, // Weight(IP): 60 => cost = 0.1 * 60 = 6 - 'portfolio/bnb-transfer': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 - 'portfolio/repay-futures-switch': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 - 'portfolio/repay-futures-negative-balance': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 - 'lending/auto-invest/plan/add': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/plan/edit': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/plan/edit-status': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/one-off': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - 'lending/auto-invest/redeem': 0.1, // Weight(IP): 1 => cost = 0.1 * 1 = 0.1 - // simple earn - 'simple-earn/flexible/subscribe': 0.1, - 'simple-earn/locked/subscribe': 0.1, - 'simple-earn/flexible/redeem': 0.1, - 'simple-earn/locked/redeem': 0.1, - 'simple-earn/flexible/setAutoSubscribe': 15, - 'simple-earn/locked/setAutoSubscribe': 15, - }, - 'put': { - 'userDataStream': 0.1, - 'userDataStream/isolated': 0.1, - }, - 'delete': { - // 'account/apiRestrictions/ipRestriction/ipList': 1, discontinued - 'margin/openOrders': 0.1, - 'margin/order': 0.006667, // Weight(UID): 1 => cost = 0.006667 - 'margin/orderList': 0.006667, - 'margin/isolated/account': 2.0001, // Weight(UID): 300 => cost = 0.006667 * 300 = 2.0001 - 'userDataStream': 0.1, - 'userDataStream/isolated': 0.1, - // brokerage API TODO NO MENTION OF RATELIMIT IN BROKERAGE DOCS - 'broker/subAccountApi': 1, - 'broker/subAccountApi/ipRestriction/ipList': 1, - 'algo/spot/order': 0.1, - 'algo/futures/order': 0.1, - 'sub-account/subAccountApi/ipRestriction/ipList': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - }, - }, - 'sapiV2': { - 'get': { - 'sub-account/futures/account': 0.1, - 'sub-account/futures/accountSummary': 1, - 'sub-account/futures/positionRisk': 0.1, - }, - 'post': { - 'sub-account/subAccountApi/ipRestriction': 20.001, // Weight(UID): 3000 => cost = 0.006667 * 3000 = 20.001 - }, - }, - 'sapiV3': { - 'get': { - 'sub-account/assets': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 - }, - 'post': { - 'asset/getUserAsset': 0.5, - }, - }, - 'sapiV4': { - 'get': { - 'sub-account/assets': 0.40002, // Weight(UID): 60 => cost = 0.006667 * 60 = 0.40002 - }, - }, - 'dapiPublic': { - 'get': { - 'ping': 1, - 'time': 1, - 'exchangeInfo': 1, - 'depth': { 'cost': 2, 'byLimit': [ [ 50, 2 ], [ 100, 5 ], [ 500, 10 ], [ 1000, 20 ] ] }, - 'trades': 5, - 'historicalTrades': 20, - 'aggTrades': 20, - 'premiumIndex': 10, - 'fundingRate': 1, - 'klines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'continuousKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'indexPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'markPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'premiumIndexKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'ticker/24hr': { 'cost': 1, 'noSymbol': 40 }, - 'ticker/price': { 'cost': 1, 'noSymbol': 2 }, - 'ticker/bookTicker': { 'cost': 2, 'noSymbol': 5 }, - 'constituents': 2, - 'openInterest': 1, - }, - }, - 'dapiData': { - 'get': { - 'delivery-price': 1, - 'openInterestHist': 1, - 'topLongShortAccountRatio': 1, - 'topLongShortPositionRatio': 1, - 'globalLongShortAccountRatio': 1, - 'takerBuySellVol': 1, - 'basis': 1, - }, - }, - 'dapiPrivate': { - 'get': { - 'positionSide/dual': 30, - 'orderAmendment': 1, - 'order': 1, - 'openOrder': 1, - 'openOrders': { 'cost': 1, 'noSymbol': 5 }, - 'allOrders': { 'cost': 20, 'noSymbol': 40 }, - 'balance': 1, - 'account': 5, - 'positionMargin/history': 1, - 'positionRisk': 1, - 'userTrades': { 'cost': 20, 'noSymbol': 40 }, - 'income': 20, - 'leverageBracket': 1, - 'forceOrders': { 'cost': 20, 'noSymbol': 50 }, - 'adlQuantile': 5, - 'commissionRate': 20, - 'income/asyn': 5, - 'income/asyn/id': 5, - 'pmExchangeInfo': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5 - 'pmAccountInfo': 0.5, // Weight(IP): 5 => cost = 0.1 * 5 = 0.5 - }, - 'post': { - 'positionSide/dual': 1, - 'order': 4, - 'batchOrders': 5, - 'countdownCancelAll': 10, - 'leverage': 1, - 'marginType': 1, - 'positionMargin': 1, - 'listenKey': 1, - }, - 'put': { - 'listenKey': 1, - 'order': 1, - 'batchOrders': 5, - }, - 'delete': { - 'order': 1, - 'allOpenOrders': 1, - 'batchOrders': 5, - 'listenKey': 1, - }, - }, - 'dapiPrivateV2': { - 'get': { - 'leverageBracket': 1, - }, - }, - 'fapiPublic': { - 'get': { - 'ping': 1, - 'time': 1, - 'exchangeInfo': 1, - 'depth': { 'cost': 2, 'byLimit': [ [ 50, 2 ], [ 100, 5 ], [ 500, 10 ], [ 1000, 20 ] ] }, - 'trades': 5, - 'historicalTrades': 20, - 'aggTrades': 20, - 'klines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'continuousKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'markPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'indexPriceKlines': { 'cost': 1, 'byLimit': [ [ 99, 1 ], [ 499, 2 ], [ 1000, 5 ], [ 10000, 10 ] ] }, - 'fundingRate': 1, - 'fundingInfo': 1, - 'premiumIndex': 1, - 'ticker/24hr': { 'cost': 1, 'noSymbol': 40 }, - 'ticker/price': { 'cost': 1, 'noSymbol': 2 }, - 'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 }, - 'openInterest': 1, - 'indexInfo': 1, - 'assetIndex': { 'cost': 1, 'noSymbol': 10 }, - 'constituents': 2, - 'apiTradingStatus': { 'cost': 1, 'noSymbol': 10 }, - 'lvtKlines': 1, - }, - }, - 'fapiData': { - 'get': { - 'delivery-price': 1, - 'openInterestHist': 1, - 'topLongShortAccountRatio': 1, - 'topLongShortPositionRatio': 1, - 'globalLongShortAccountRatio': 1, - 'takerlongshortRatio': 1, - 'basis': 1, - }, - }, - 'fapiPrivate': { - 'get': { - 'forceOrders': { 'cost': 20, 'noSymbol': 50 }, - 'allOrders': 5, - 'openOrder': 1, - 'openOrders': 1, - 'order': 1, - 'account': 5, - 'balance': 5, - 'leverageBracket': 1, - 'positionMargin/history': 1, - 'positionRisk': 5, - 'positionSide/dual': 30, - 'userTrades': 5, - 'income': 30, - 'commissionRate': 20, - 'apiTradingStatus': 1, - 'multiAssetsMargin': 30, - // broker endpoints - 'apiReferral/ifNewUser': 1, - 'apiReferral/customization': 1, - 'apiReferral/userCustomization': 1, - 'apiReferral/traderNum': 1, - 'apiReferral/overview': 1, - 'apiReferral/tradeVol': 1, - 'apiReferral/rebateVol': 1, - 'apiReferral/traderSummary': 1, - 'adlQuantile': 5, - 'pmAccountInfo': 5, - 'orderAmendment': 1, - 'income/asyn': 1000, - 'income/asyn/id': 10, - 'order/asyn': 1000, - 'order/asyn/id': 10, - 'trade/asyn': 1000, - 'trade/asyn/id': 10, - }, - 'post': { - 'batchOrders': 5, - 'positionSide/dual': 1, - 'positionMargin': 1, - 'marginType': 1, - 'order': 4, - 'leverage': 1, - 'listenKey': 1, - 'countdownCancelAll': 10, - 'multiAssetsMargin': 1, - // broker endpoints - 'apiReferral/customization': 1, - 'apiReferral/userCustomization': 1, - }, - 'put': { - 'listenKey': 1, - 'order': 1, - 'batchOrders': 5, - }, - 'delete': { - 'batchOrders': 1, - 'order': 1, - 'allOpenOrders': 1, - 'listenKey': 1, - }, - }, - 'fapiPublicV2': { - 'get': { - 'ticker/price': 0, - }, - }, - 'fapiPrivateV2': { - 'get': { - 'account': 1, - 'balance': 1, - 'positionRisk': 1, - }, - }, - 'eapiPublic': { - 'get': { - 'ping': 1, - 'time': 1, - 'exchangeInfo': 1, - 'index': 1, - 'ticker': 5, - 'mark': 5, - 'depth': 1, - 'klines': 1, - 'trades': 5, - 'historicalTrades': 20, - 'exerciseHistory': 3, - 'openInterest': 3, - }, - }, - 'eapiPrivate': { - 'get': { - 'account': 3, - 'position': 5, - 'openOrders': { 'cost': 1, 'noSymbol': 40 }, - 'historyOrders': 3, - 'userTrades': 5, - 'exerciseRecord': 5, - 'bill': 1, - 'income/asyn': 5, - 'income/asyn/id': 5, - 'marginAccount': 3, - 'mmp': 1, - 'countdownCancelAll': 1, - 'order': 1, - }, - 'post': { - 'order': 1, - 'batchOrders': 5, - 'listenKey': 1, - 'mmpSet': 1, - 'mmpReset': 1, - 'countdownCancelAll': 1, - 'countdownCancelAllHeartBeat': 10, - }, - 'put': { - 'listenKey': 1, - }, - 'delete': { - 'order': 1, - 'batchOrders': 1, - 'allOpenOrders': 1, - 'allOpenOrdersByUnderlying': 1, - 'listenKey': 1, - }, - }, - 'public': { - // IP (api) request rate limit of 6000 per minute - // 1 IP (api) => cost = 0.2 => (1000 / (50 * 0.2)) * 60 = 6000 - 'get': { - 'ping': 0.2, // Weight(IP): 1 => cost = 0.2 * 1 = 0.2 - 'time': 0.2, - 'depth': { 'cost': 1, 'byLimit': [ [ 100, 1 ], [ 500, 5 ], [ 1000, 10 ], [ 5000, 50 ] ] }, - 'trades': 2, // Weight(IP): 10 => cost = 0.2 * 10 = 2 - 'aggTrades': 0.4, - 'historicalTrades': 2, // Weight(IP): 10 => cost = 0.2 * 10 = 2 - 'klines': 0.4, - 'uiKlines': 0.4, - 'ticker/24hr': { 'cost': 0.4, 'noSymbol': 16 }, - 'ticker': { 'cost': 0.4, 'noSymbol': 16 }, - 'ticker/tradingDay': 0.8, - 'ticker/price': { 'cost': 0.4, 'noSymbol': 0.8 }, - 'ticker/bookTicker': { 'cost': 0.4, 'noSymbol': 0.8 }, - 'exchangeInfo': 4, // Weight(IP): 20 => cost = 0.2 * 20 = 4 - 'avgPrice': 0.4, - }, - 'put': { - 'userDataStream': 0.4, - }, - 'post': { - 'userDataStream': 0.4, - }, - 'delete': { - 'userDataStream': 0.4, - }, - }, - 'private': { - 'get': { - 'allOrderList': 4, // oco Weight(IP): 20 => cost = 0.2 * 20 = 4 - 'openOrderList': 1.2, // oco Weight(IP): 6 => cost = 0.2 * 6 = 1.2 - 'orderList': 0.8, // oco - 'order': 0.8, - 'openOrders': { 'cost': 1.2, 'noSymbol': 16 }, - 'allOrders': 4, - 'account': 4, - 'myTrades': 4, - 'rateLimit/order': 8, // Weight(IP): 40 => cost = 0.2 * 40 = 8 - 'myPreventedMatches': 4, // Weight(IP): 20 => cost = 0.2 * 20 = 4 - 'myAllocations': 4, - 'account/commission': 4, - }, - 'post': { - 'order/oco': 0.2, - 'sor/order': 0.2, - 'sor/order/test': 0.2, - 'order': 0.2, - 'order/cancelReplace': 0.2, - 'order/test': 0.2, - }, - 'delete': { - 'openOrders': 0.2, - 'orderList': 0.2, // oco - 'order': 0.2, - }, - }, - 'papi': { - 'get': { - 'um/order': 1, // 1 - 'um/openOrder': 1, // 1 - 'um/openOrders': 1, // 1 - 'um/allOrders': 5, // 5 - 'cm/order': 1, // 1 - 'cm/openOrder': 1, // 1 - 'cm/openOrders': 1, // 1 - 'cm/allOrders': 20, // 20 - 'um/conditional/openOrder': 1, - 'um/conditional/openOrders': 40, - 'um/conditional/orderHistory': 1, - 'um/conditional/allOrders': 40, - 'cm/conditional/openOrder': 1, - 'cm/conditional/openOrders': 40, - 'cm/conditional/orderHistory': 1, - 'cm/conditional/allOrders': 40, - 'margin/order': 5, - 'margin/openOrders': 5, - 'margin/allOrders': 100, - 'margin/orderList': 5, - 'margin/allOrderList': 100, - 'margin/openOrderList': 5, - 'margin/myTrades': 5, - 'balance': 20, // 20 - 'account': 20, // 20 - 'margin/maxBorrowable': 5, // 5 - 'margin/maxWithdraw': 5, // 5 - 'um/positionRisk': 5, // 5 - 'cm/positionRisk': 1, // 1 - 'um/positionSide/dual': 30, // 30 - 'cm/positionSide/dual': 30, // 30 - 'um/userTrades': 5, // 5 - 'cm/userTrades': 20, // 20 - 'um/leverageBracket': 1, // 1 - 'cm/leverageBracket': 1, // 1 - 'margin/forceOrders': 1, // 1 - 'um/forceOrders': 20, // 20 - 'cm/forceOrders': 20, // 20 - 'um/apiTradingStatus': 1, // 1 - 'um/commissionRate': 20, // 20 - 'cm/commissionRate': 20, // 20 - 'margin/marginLoan': 10, - 'margin/repayLoan': 10, - 'margin/marginInterestHistory': 1, - 'portfolio/interest-history': 50, // 50 - 'um/income': 30, - 'cm/income': 30, - 'um/account': 5, - 'cm/account': 5, - 'repay-futures-switch': 3, // Weight(IP): 30 => cost = 0.1 * 30 = 3 - 'um/adlQuantile': 5, - 'cm/adlQuantile': 5, - }, - 'post': { - 'um/order': 1, // 0 - 'um/conditional/order': 1, - 'cm/order': 1, // 0 - 'cm/conditional/order': 1, - 'margin/order': 0.0133, // Weight(UID): 2 => cost = 0.006667 * 2 = 0.013334 - 'marginLoan': 0.1333, // Weight(UID): 20 => cost = 0.006667 * 20 = 0.13334 - 'repayLoan': 0.1333, // Weight(UID): 20 => cost = 0.006667 * 20 = 0.13334 - 'margin/order/oco': 0.0400, // Weight(UID): 6 => cost = 0.006667 * 6 = 0.040002 - 'um/leverage': 1, // 1 - 'cm/leverage': 1, // 1 - 'um/positionSide/dual': 1, // 1 - 'cm/positionSide/dual': 1, // 1 - 'auto-collection': 0.6667, // Weight(UID): 100 => cost = 0.006667 * 100 = 0.6667 - 'bnb-transfer': 0.6667, // Weight(UID): 100 => cost = 0.006667 * 100 = 0.6667 - 'repay-futures-switch': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 - 'repay-futures-negative-balance': 150, // Weight(IP): 1500 => cost = 0.1 * 1500 = 150 - 'listenKey': 1, // 1 - 'asset-collection': 3, - }, - 'put': { - 'listenKey': 1, // 1 - }, - 'delete': { - 'um/order': 1, // 1 - 'um/conditional/order': 1, - 'um/allOpenOrders': 1, // 1 - 'um/conditional/allOpenOrders': 1, - 'cm/order': 1, // 1 - 'cm/conditional/order': 1, - 'cm/allOpenOrders': 1, // 1 - 'cm/conditional/allOpenOrders': 1, - 'margin/order': 1, // Weight(IP): 10 => cost = 0.1 * 10 = 1 - 'margin/allOpenOrders': 5, // 5 - 'margin/orderList': 2, // 2 - 'listenKey': 1, // 1 + 'v4': { + 'public': { + 'get': [ + 'ping', + 'status', + 'time', + 'currencies', + 'markets', + 'ticker', + 'trades', + 'orderbook', + 'charts', + 'charts/{pair}', + ], + }, + 'private': { + 'get': [ + 'transactions', + 'balances', + 'keys', + 'sessions', + 'profile', + ], + 'post': [ + 'keys', + 'orders', + ], + 'delete': [ + 'keys/{id}', + ], }, }, }, @@ -1024,990 +203,167 @@ export default class youngplatform extends Exchange { 'taker': this.parseNumber ('0.001'), 'maker': this.parseNumber ('0.001'), }, - 'linear': { - 'trading': { - 'feeSide': 'quote', - 'tierBased': true, - 'percentage': true, - 'taker': this.parseNumber ('0.000400'), - 'maker': this.parseNumber ('0.000200'), - 'tiers': { - 'taker': [ - [ this.parseNumber ('0'), this.parseNumber ('0.000400') ], - [ this.parseNumber ('250'), this.parseNumber ('0.000400') ], - [ this.parseNumber ('2500'), this.parseNumber ('0.000350') ], - [ this.parseNumber ('7500'), this.parseNumber ('0.000320') ], - [ this.parseNumber ('22500'), this.parseNumber ('0.000300') ], - [ this.parseNumber ('50000'), this.parseNumber ('0.000270') ], - [ this.parseNumber ('100000'), this.parseNumber ('0.000250') ], - [ this.parseNumber ('200000'), this.parseNumber ('0.000220') ], - [ this.parseNumber ('400000'), this.parseNumber ('0.000200') ], - [ this.parseNumber ('750000'), this.parseNumber ('0.000170') ], - ], - 'maker': [ - [ this.parseNumber ('0'), this.parseNumber ('0.000200') ], - [ this.parseNumber ('250'), this.parseNumber ('0.000160') ], - [ this.parseNumber ('2500'), this.parseNumber ('0.000140') ], - [ this.parseNumber ('7500'), this.parseNumber ('0.000120') ], - [ this.parseNumber ('22500'), this.parseNumber ('0.000100') ], - [ this.parseNumber ('50000'), this.parseNumber ('0.000080') ], - [ this.parseNumber ('100000'), this.parseNumber ('0.000060') ], - [ this.parseNumber ('200000'), this.parseNumber ('0.000040') ], - [ this.parseNumber ('400000'), this.parseNumber ('0.000020') ], - [ this.parseNumber ('750000'), this.parseNumber ('0') ], - ], - }, - }, - }, - 'inverse': { - 'trading': { - 'feeSide': 'base', - 'tierBased': true, - 'percentage': true, - 'taker': this.parseNumber ('0.000500'), - 'maker': this.parseNumber ('0.000100'), - 'tiers': { - 'taker': [ - [ this.parseNumber ('0'), this.parseNumber ('0.000500') ], - [ this.parseNumber ('250'), this.parseNumber ('0.000450') ], - [ this.parseNumber ('2500'), this.parseNumber ('0.000400') ], - [ this.parseNumber ('7500'), this.parseNumber ('0.000300') ], - [ this.parseNumber ('22500'), this.parseNumber ('0.000250') ], - [ this.parseNumber ('50000'), this.parseNumber ('0.000240') ], - [ this.parseNumber ('100000'), this.parseNumber ('0.000240') ], - [ this.parseNumber ('200000'), this.parseNumber ('0.000240') ], - [ this.parseNumber ('400000'), this.parseNumber ('0.000240') ], - [ this.parseNumber ('750000'), this.parseNumber ('0.000240') ], - ], - 'maker': [ - [ this.parseNumber ('0'), this.parseNumber ('0.000100') ], - [ this.parseNumber ('250'), this.parseNumber ('0.000080') ], - [ this.parseNumber ('2500'), this.parseNumber ('0.000050') ], - [ this.parseNumber ('7500'), this.parseNumber ('0.0000030') ], - [ this.parseNumber ('22500'), this.parseNumber ('0') ], - [ this.parseNumber ('50000'), this.parseNumber ('-0.000050') ], - [ this.parseNumber ('100000'), this.parseNumber ('-0.000060') ], - [ this.parseNumber ('200000'), this.parseNumber ('-0.000070') ], - [ this.parseNumber ('400000'), this.parseNumber ('-0.000080') ], - [ this.parseNumber ('750000'), this.parseNumber ('-0.000090') ], - ], - }, - }, - }, - 'option': {}, }, 'commonCurrencies': { - 'BCC': 'BCC', // kept for backward-compatibility https://github.com/ccxt/ccxt/issues/4848 - 'YOYO': 'YOYOW', + 'BCC': 'BCC', }, 'precisionMode': DECIMAL_PLACES, - // exchange-specific options 'options': { - 'sandboxMode': false, - 'fetchMarkets': [ - 'spot', // allows CORS in browsers - 'linear', // allows CORS in browsers - 'inverse', // allows CORS in browsers - // 'option', // does not allow CORS, enable outside of the browser only - ], - 'fetchCurrencies': true, // this is a private call and it requires API keys - // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades, eapiPublicGetTrades - 'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery', 'option' - 'defaultSubType': undefined, // 'linear', 'inverse' - 'hasAlreadyAuthenticatedSuccessfully': false, - 'warnOnFetchOpenOrdersWithoutSymbol': true, - // not an error - // https://github.com/ccxt/ccxt/issues/11268 - // https://github.com/ccxt/ccxt/pull/11624 - // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request - // binanceusdm - 'throwMarginModeAlreadySet': false, - 'fetchPositions': 'positionRisk', // or 'account' or 'option' - 'recvWindow': 10 * 1000, // 10 sec - 'timeDifference': 0, // the difference between system clock and Binance clock - 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation - 'newOrderRespType': { - 'market': 'FULL', // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills - 'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit) - }, - 'quoteOrderQty': true, // whether market orders support amounts in quote currency - 'broker': { - 'spot': 'x-R4BD3S82', - 'margin': 'x-R4BD3S82', - 'future': 'x-xcKtGhcu', - 'delivery': 'x-xcKtGhcu', - 'swap': 'x-xcKtGhcu', - 'option': 'x-xcKtGhcu', - }, - 'accountsByType': { - 'main': 'MAIN', - 'spot': 'MAIN', - 'funding': 'FUNDING', - 'margin': 'MARGIN', - 'cross': 'MARGIN', - 'future': 'UMFUTURE', // backwards compatibility - 'delivery': 'CMFUTURE', // backwards compatbility - 'linear': 'UMFUTURE', - 'inverse': 'CMFUTURE', - 'option': 'OPTION', - }, - 'accountsById': { - 'MAIN': 'spot', - 'FUNDING': 'funding', - 'MARGIN': 'margin', - 'UMFUTURE': 'linear', - 'CMFUTURE': 'inverse', - 'OPTION': 'option', - }, 'networks': { 'ERC20': 'ETH', - 'TRC20': 'TRX', - 'BEP2': 'BNB', 'BEP20': 'BSC', - 'OMNI': 'OMNI', - 'EOS': 'EOS', - 'SPL': 'SOL', - }, - // keeping this object for backward-compatibility - 'reverseNetworks': { - 'tronscan.org': 'TRC20', - 'etherscan.io': 'ERC20', - 'bscscan.com': 'BSC', - 'explorer.binance.org': 'BEP2', - 'bithomp.com': 'XRP', - 'bloks.io': 'EOS', - 'stellar.expert': 'XLM', - 'blockchair.com/bitcoin': 'BTC', - 'blockchair.com/bitcoin-cash': 'BCH', - 'blockchair.com/ecash': 'XEC', - 'explorer.litecoin.net': 'LTC', - 'explorer.avax.network': 'AVAX', - 'solscan.io': 'SOL', - 'polkadot.subscan.io': 'DOT', - 'dashboard.internetcomputer.org': 'ICP', - 'explorer.chiliz.com': 'CHZ', - 'cardanoscan.io': 'ADA', - 'mainnet.theoan.com': 'AION', - 'algoexplorer.io': 'ALGO', - 'explorer.ambrosus.com': 'AMB', - 'viewblock.io/zilliqa': 'ZIL', - 'viewblock.io/arweave': 'AR', - 'explorer.ark.io': 'ARK', - 'atomscan.com': 'ATOM', - 'www.mintscan.io': 'CTK', - 'explorer.bitcoindiamond.org': 'BCD', - 'btgexplorer.com': 'BTG', - 'bts.ai': 'BTS', - 'explorer.celo.org': 'CELO', - 'explorer.nervos.org': 'CKB', - 'cerebro.cortexlabs.ai': 'CTXC', - 'chainz.cryptoid.info': 'VIA', - 'explorer.dcrdata.org': 'DCR', - 'digiexplorer.info': 'DGB', - 'dock.subscan.io': 'DOCK', - 'dogechain.info': 'DOGE', - 'explorer.elrond.com': 'EGLD', - 'blockscout.com': 'ETC', - 'explore-fetchhub.fetch.ai': 'FET', - 'filfox.info': 'FIL', - 'fio.bloks.io': 'FIO', - 'explorer.firo.org': 'FIRO', - 'neoscan.io': 'NEO', - 'ftmscan.com': 'FTM', - 'explorer.gochain.io': 'GO', - 'block.gxb.io': 'GXS', - 'hash-hash.info': 'HBAR', - 'www.hiveblockexplorer.com': 'HIVE', - 'explorer.helium.com': 'HNT', - 'tracker.icon.foundation': 'ICX', - 'www.iostabc.com': 'IOST', - 'explorer.iota.org': 'IOTA', - 'iotexscan.io': 'IOTX', - 'irishub.iobscan.io': 'IRIS', - 'kava.mintscan.io': 'KAVA', - 'scope.klaytn.com': 'KLAY', - 'kmdexplorer.io': 'KMD', - 'kusama.subscan.io': 'KSM', - 'explorer.lto.network': 'LTO', - 'polygonscan.com': 'POLYGON', - 'explorer.ont.io': 'ONT', - 'minaexplorer.com': 'MINA', - 'nanolooker.com': 'NANO', - 'explorer.nebulas.io': 'NAS', - 'explorer.nbs.plus': 'NBS', - 'explorer.nebl.io': 'NEBL', - 'nulscan.io': 'NULS', - 'nxscan.com': 'NXS', - 'explorer.harmony.one': 'ONE', - 'explorer.poa.network': 'POA', - 'qtum.info': 'QTUM', - 'explorer.rsk.co': 'RSK', - 'www.oasisscan.com': 'ROSE', - 'ravencoin.network': 'RVN', - 'sc.tokenview.com': 'SC', - 'secretnodes.com': 'SCRT', - 'explorer.skycoin.com': 'SKY', - 'steemscan.com': 'STEEM', - 'explorer.stacks.co': 'STX', - 'www.thetascan.io': 'THETA', - 'scan.tomochain.com': 'TOMO', - 'explore.vechain.org': 'VET', - 'explorer.vite.net': 'VITE', - 'www.wanscan.org': 'WAN', - 'wavesexplorer.com': 'WAVES', - 'wax.eosx.io': 'WAXP', - 'waltonchain.pro': 'WTC', - 'chain.nem.ninja': 'XEM', - 'verge-blockchain.info': 'XVG', - 'explorer.yoyow.org': 'YOYOW', - 'explorer.zcha.in': 'ZEC', - 'explorer.zensystem.io': 'ZEN', - }, - 'networksById': { - 'tronscan.org': 'TRC20', - 'etherscan.io': 'ERC20', - 'bscscan.com': 'BSC', - 'explorer.binance.org': 'BEP2', - 'bithomp.com': 'XRP', - 'bloks.io': 'EOS', - 'stellar.expert': 'XLM', - 'blockchair.com/bitcoin': 'BTC', - 'blockchair.com/bitcoin-cash': 'BCH', - 'blockchair.com/ecash': 'XEC', - 'explorer.litecoin.net': 'LTC', - 'explorer.avax.network': 'AVAX', - 'solscan.io': 'SOL', - 'polkadot.subscan.io': 'DOT', - 'dashboard.internetcomputer.org': 'ICP', - 'explorer.chiliz.com': 'CHZ', - 'cardanoscan.io': 'ADA', - 'mainnet.theoan.com': 'AION', - 'algoexplorer.io': 'ALGO', - 'explorer.ambrosus.com': 'AMB', - 'viewblock.io/zilliqa': 'ZIL', - 'viewblock.io/arweave': 'AR', - 'explorer.ark.io': 'ARK', - 'atomscan.com': 'ATOM', - 'www.mintscan.io': 'CTK', - 'explorer.bitcoindiamond.org': 'BCD', - 'btgexplorer.com': 'BTG', - 'bts.ai': 'BTS', - 'explorer.celo.org': 'CELO', - 'explorer.nervos.org': 'CKB', - 'cerebro.cortexlabs.ai': 'CTXC', - 'chainz.cryptoid.info': 'VIA', - 'explorer.dcrdata.org': 'DCR', - 'digiexplorer.info': 'DGB', - 'dock.subscan.io': 'DOCK', - 'dogechain.info': 'DOGE', - 'explorer.elrond.com': 'EGLD', - 'blockscout.com': 'ETC', - 'explore-fetchhub.fetch.ai': 'FET', - 'filfox.info': 'FIL', - 'fio.bloks.io': 'FIO', - 'explorer.firo.org': 'FIRO', - 'neoscan.io': 'NEO', - 'ftmscan.com': 'FTM', - 'explorer.gochain.io': 'GO', - 'block.gxb.io': 'GXS', - 'hash-hash.info': 'HBAR', - 'www.hiveblockexplorer.com': 'HIVE', - 'explorer.helium.com': 'HNT', - 'tracker.icon.foundation': 'ICX', - 'www.iostabc.com': 'IOST', - 'explorer.iota.org': 'IOTA', - 'iotexscan.io': 'IOTX', - 'irishub.iobscan.io': 'IRIS', - 'kava.mintscan.io': 'KAVA', - 'scope.klaytn.com': 'KLAY', - 'kmdexplorer.io': 'KMD', - 'kusama.subscan.io': 'KSM', - 'explorer.lto.network': 'LTO', - 'polygonscan.com': 'POLYGON', - 'explorer.ont.io': 'ONT', - 'minaexplorer.com': 'MINA', - 'nanolooker.com': 'NANO', - 'explorer.nebulas.io': 'NAS', - 'explorer.nbs.plus': 'NBS', - 'explorer.nebl.io': 'NEBL', - 'nulscan.io': 'NULS', - 'nxscan.com': 'NXS', - 'explorer.harmony.one': 'ONE', - 'explorer.poa.network': 'POA', - 'qtum.info': 'QTUM', - 'explorer.rsk.co': 'RSK', - 'www.oasisscan.com': 'ROSE', - 'ravencoin.network': 'RVN', - 'sc.tokenview.com': 'SC', - 'secretnodes.com': 'SCRT', - 'explorer.skycoin.com': 'SKY', - 'steemscan.com': 'STEEM', - 'explorer.stacks.co': 'STX', - 'www.thetascan.io': 'THETA', - 'scan.tomochain.com': 'TOMO', - 'explore.vechain.org': 'VET', - 'explorer.vite.net': 'VITE', - 'www.wanscan.org': 'WAN', - 'wavesexplorer.com': 'WAVES', - 'wax.eosx.io': 'WAXP', - 'waltonchain.pro': 'WTC', - 'chain.nem.ninja': 'XEM', - 'verge-blockchain.info': 'XVG', - 'explorer.yoyow.org': 'YOYOW', - 'explorer.zcha.in': 'ZEC', - 'explorer.zensystem.io': 'ZEN', - }, - 'impliedNetworks': { - 'ETH': { 'ERC20': 'ETH' }, - 'TRX': { 'TRC20': 'TRX' }, - }, - 'legalMoney': { - 'MXN': true, - 'UGX': true, - 'SEK': true, - 'CHF': true, - 'VND': true, - 'AED': true, - 'DKK': true, - 'KZT': true, - 'HUF': true, - 'PEN': true, - 'PHP': true, - 'USD': true, - 'TRY': true, - 'EUR': true, - 'NGN': true, - 'PLN': true, - 'BRL': true, - 'ZAR': true, - 'KES': true, - 'ARS': true, - 'RUB': true, - 'AUD': true, - 'NOK': true, - 'CZK': true, - 'GBP': true, - 'UAH': true, - 'GHS': true, - 'HKD': true, - 'CAD': true, - 'INR': true, - 'JPY': true, - 'NZD': true, - }, - 'legalMoneyCurrenciesById': { - 'BUSD': 'USD', }, }, - // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2 'exceptions': { 'exact': { - 'System is under maintenance.': OnMaintenance, // {"code":1,"msg":"System is under maintenance."} - 'System abnormality': ExchangeError, // {"code":-1000,"msg":"System abnormality"} - 'You are not authorized to execute this request.': PermissionDenied, // {"msg":"You are not authorized to execute this request."} - 'API key does not exist': AuthenticationError, - 'Order would trigger immediately.': OrderImmediatelyFillable, - 'Stop price would trigger immediately.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Stop price would trigger immediately."} - 'Order would immediately match and take.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Order would immediately match and take."} - 'Account has insufficient balance for requested action.': InsufficientFunds, - 'Rest API trading is not enabled.': ExchangeNotAvailable, - 'This account may not place or cancel orders.': ExchangeNotAvailable, - "You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false} - 'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."} - 'Too many requests. Please try again later.': DDoSProtection, // {"msg":"Too many requests. Please try again later.","success":false} - 'This action is disabled on this account.': AccountSuspended, // {"code":-2011,"msg":"This action is disabled on this account."} - 'Limit orders require GTC for this phase.': BadRequest, - 'This order type is not possible in this trading phase.': BadRequest, - 'This type of sub-account exceeds the maximum number limit': BadRequest, // {"code":-9000,"msg":"This type of sub-account exceeds the maximum number limit"} - 'This symbol is restricted for this account.': PermissionDenied, - 'This symbol is not permitted for this account.': PermissionDenied, // {"code":-2010,"msg":"This symbol is not permitted for this account."} - '-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."} - '-1001': ExchangeNotAvailable, // {"code":-1001,"msg":"'Internal error; unable to process your request. Please try again.'"} - '-1002': AuthenticationError, // {"code":-1002,"msg":"'You are not authorized to execute this request.'"} - '-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."} - '-1004': DDoSProtection, // {"code":-1004,"msg":"Server is busy, please wait and try again"} - '-1005': PermissionDenied, // {"code":-1005,"msg":"No such IP has been white listed"} - '-1006': BadResponse, // {"code":-1006,"msg":"An unexpected response was received from the message bus. Execution status unknown."} - '-1007': RequestTimeout, // {"code":-1007,"msg":"Timeout waiting for response from backend server. Send status unknown; execution status unknown."} - '-1010': BadResponse, // {"code":-1010,"msg":"ERROR_MSG_RECEIVED."} - '-1011': PermissionDenied, // {"code":-1011,"msg":"This IP cannot access this route."} - '-1013': InvalidOrder, // {"code":-1013,"msg":"createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL"} - '-1014': InvalidOrder, // {"code":-1014,"msg":"Unsupported order combination."} - '-1015': RateLimitExceeded, // {"code":-1015,"msg":"'Too many new orders; current limit is %s orders per %s.'"} - '-1016': ExchangeNotAvailable, // {"code":-1016,"msg":"'This service is no longer available.',"} - '-1020': BadRequest, // {"code":-1020,"msg":"'This operation is not supported.'"} - '-1021': InvalidNonce, // {"code":-1021,"msg":"'your time is ahead of server'"} - '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."} - '-1023': BadRequest, // {"code":-1023,"msg":"Start time is greater than end time."} - '-1099': AuthenticationError, // {"code":-1099,"msg":"Not found, authenticated, or authorized"} - '-1100': BadRequest, // {"code":-1100,"msg":"createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'"} - '-1101': BadRequest, // {"code":-1101,"msg":"Too many parameters; expected %s and received %s."} - '-1102': BadRequest, // {"code":-1102,"msg":"Param %s or %s must be sent, but both were empty"} - '-1103': BadRequest, // {"code":-1103,"msg":"An unknown parameter was sent."} - '-1104': BadRequest, // {"code":-1104,"msg":"Not all sent parameters were read, read 8 parameters but was sent 9"} - '-1105': BadRequest, // {"code":-1105,"msg":"Parameter %s was empty."} - '-1106': BadRequest, // {"code":-1106,"msg":"Parameter %s sent when not required."} - '-1108': BadRequest, // {"code":-1108,"msg":"Invalid asset."} - '-1109': AuthenticationError, // {"code":-1109,"msg":"Invalid account."} - '-1110': BadRequest, // {"code":-1110,"msg":"Invalid symbolType."} - '-1111': BadRequest, // {"code":-1111,"msg":"Precision is over the maximum defined for this asset."} - '-1112': InvalidOrder, // {"code":-1112,"msg":"No orders on book for symbol."} - '-1113': BadRequest, // {"code":-1113,"msg":"Withdrawal amount must be negative."} - '-1114': BadRequest, // {"code":-1114,"msg":"TimeInForce parameter sent when not required."} - '-1115': BadRequest, // {"code":-1115,"msg":"Invalid timeInForce."} - '-1116': BadRequest, // {"code":-1116,"msg":"Invalid orderType."} - '-1117': BadRequest, // {"code":-1117,"msg":"Invalid side."} - '-1118': BadRequest, // {"code":-1118,"msg":"New client order ID was empty."} - '-1119': BadRequest, // {"code":-1119,"msg":"Original client order ID was empty."} - '-1120': BadRequest, // {"code":-1120,"msg":"Invalid interval."} - '-1121': BadSymbol, // {"code":-1121,"msg":"Invalid symbol."} - '-1125': AuthenticationError, // {"code":-1125,"msg":"This listenKey does not exist."} - '-1127': BadRequest, // {"code":-1127,"msg":"More than %s hours between startTime and endTime."} - '-1128': BadRequest, // {"code":-1128,"msg":"{"code":-1128,"msg":"Combination of optional parameters invalid."}"} - '-1130': BadRequest, // {"code":-1130,"msg":"Data sent for paramter %s is not valid."} - '-1131': BadRequest, // {"code":-1131,"msg":"recvWindow must be less than 60000"} - '-1135': BadRequest, // This error code will occur if a parameter requiring a JSON object is invalid. - '-1136': BadRequest, // {"code":-1136,"msg":"Invalid newOrderRespType"} - '-2008': AuthenticationError, // {"code":-2008,"msg":"Invalid Api-Key ID."} - '-2010': ExchangeError, // {"code":-2010,"msg":"generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc..."} - '-2011': OrderNotFound, // {"code":-2011,"msg":"cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'"} - '-2013': OrderNotFound, // {"code":-2013,"msg":"fetchOrder (1, 'BTC/USDT') -> 'Order does not exist'"} - '-2014': AuthenticationError, // {"code":-2014,"msg":"API-key format invalid."} - '-2015': AuthenticationError, // {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} - '-2016': BadRequest, // {"code":-2016,"msg":"No trading window could be found for the symbol. Try ticker/24hrs instead."} - '-2018': InsufficientFunds, // {"code":-2018,"msg":"Balance is insufficient"} - '-2019': InsufficientFunds, // {"code":-2019,"msg":"Margin is insufficient."} - '-2020': OrderNotFillable, // {"code":-2020,"msg":"Unable to fill."} - '-2021': OrderImmediatelyFillable, // {"code":-2021,"msg":"Order would immediately trigger."} - '-2022': InvalidOrder, // {"code":-2022,"msg":"ReduceOnly Order is rejected."} - '-2023': InsufficientFunds, // {"code":-2023,"msg":"User in liquidation mode now."} - '-2024': InsufficientFunds, // {"code":-2024,"msg":"Position is not sufficient."} - '-2025': InvalidOrder, // {"code":-2025,"msg":"Reach max open order limit."} - '-2026': InvalidOrder, // {"code":-2026,"msg":"This OrderType is not supported when reduceOnly."} - '-2027': InvalidOrder, // {"code":-2027,"msg":"Exceeded the maximum allowable position at current leverage."} - '-2028': InsufficientFunds, // {"code":-2028,"msg":"Leverage is smaller than permitted: insufficient margin balance"} - '-3000': ExchangeError, // {"code":-3000,"msg":"Internal server error."} - '-3001': AuthenticationError, // {"code":-3001,"msg":"Please enable 2FA first."} - '-3002': BadSymbol, // {"code":-3002,"msg":"We don't have this asset."} - '-3003': BadRequest, // {"code":-3003,"msg":"Margin account does not exist."} - '-3004': ExchangeError, // {"code":-3004,"msg":"Trade not allowed."} - '-3005': InsufficientFunds, // {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."} - '-3006': InsufficientFunds, // {"code":-3006,"msg":"Your borrow amount has exceed maximum borrow amount."} - '-3007': ExchangeError, // {"code":-3007,"msg":"You have pending transaction, please try again later.."} - '-3008': InsufficientFunds, // {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."} - '-3009': BadRequest, // {"code":-3009,"msg":"This asset are not allowed to transfer into margin account currently."} - '-3010': BadRequest, // {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."} - '-3011': BadRequest, // {"code":-3011,"msg":"Your input date is invalid."} - '-3012': InsufficientFunds, // {"code":-3012,"msg":"Borrow is banned for this asset."} - '-3013': BadRequest, // {"code":-3013,"msg":"Borrow amount less than minimum borrow amount."} - '-3014': AccountSuspended, // {"code":-3014,"msg":"Borrow is banned for this account."} - '-3015': BadRequest, // {"code":-3015,"msg":"Repay amount exceeds borrow amount."} - '-3016': BadRequest, // {"code":-3016,"msg":"Repay amount less than minimum repay amount."} - '-3017': ExchangeError, // {"code":-3017,"msg":"This asset are not allowed to transfer into margin account currently."} - '-3018': AccountSuspended, // {"code":-3018,"msg":"Transferring in has been banned for this account."} - '-3019': AccountSuspended, // {"code":-3019,"msg":"Transferring out has been banned for this account."} - '-3020': InsufficientFunds, // {"code":-3020,"msg":"Transfer out amount exceeds max amount."} - '-3021': BadRequest, // {"code":-3021,"msg":"Margin account are not allowed to trade this trading pair."} - '-3022': AccountSuspended, // {"code":-3022,"msg":"You account's trading is banned."} - '-3023': BadRequest, // {"code":-3023,"msg":"You can't transfer out/place order under current margin level."} - '-3024': ExchangeError, // {"code":-3024,"msg":"The unpaid debt is too small after this repayment."} - '-3025': BadRequest, // {"code":-3025,"msg":"Your input date is invalid."} - '-3026': BadRequest, // {"code":-3026,"msg":"Your input param is invalid."} - '-3027': BadSymbol, // {"code":-3027,"msg":"Not a valid margin asset."} - '-3028': BadSymbol, // {"code":-3028,"msg":"Not a valid margin pair."} - '-3029': ExchangeError, // {"code":-3029,"msg":"Transfer failed."} - '-3036': AccountSuspended, // {"code":-3036,"msg":"This account is not allowed to repay."} - '-3037': ExchangeError, // {"code":-3037,"msg":"PNL is clearing. Wait a second."} - '-3038': BadRequest, // {"code":-3038,"msg":"Listen key not found."} - '-3041': InsufficientFunds, // {"code":-3041,"msg":"Balance is not enough"} - '-3042': BadRequest, // {"code":-3042,"msg":"PriceIndex not available for this margin pair."} - '-3043': BadRequest, // {"code":-3043,"msg":"Transferring in not allowed."} - '-3044': DDoSProtection, // {"code":-3044,"msg":"System busy."} - '-3045': ExchangeError, // {"code":-3045,"msg":"The system doesn't have enough asset now."} - '-3999': ExchangeError, // {"code":-3999,"msg":"This function is only available for invited users."} - '-4001': BadRequest, // {"code":-4001 ,"msg":"Invalid operation."} - '-4002': BadRequest, // {"code":-4002 ,"msg":"Invalid get."} - '-4003': BadRequest, // {"code":-4003 ,"msg":"Your input email is invalid."} - '-4004': AuthenticationError, // {"code":-4004,"msg":"You don't login or auth."} - '-4005': RateLimitExceeded, // {"code":-4005 ,"msg":"Too many new requests."} - '-4006': BadRequest, // {"code":-4006 ,"msg":"Support main account only."} - '-4007': BadRequest, // {"code":-4007 ,"msg":"Address validation is not passed."} - '-4008': BadRequest, // {"code":-4008 ,"msg":"Address tag validation is not passed."} - '-4010': BadRequest, // {"code":-4010 ,"msg":"White list mail has been confirmed."} // [TODO] possible bug: it should probably be "has not been confirmed" - '-4011': BadRequest, // {"code":-4011 ,"msg":"White list mail is invalid."} - '-4012': BadRequest, // {"code":-4012 ,"msg":"White list is not opened."} - '-4013': AuthenticationError, // {"code":-4013 ,"msg":"2FA is not opened."} - '-4014': PermissionDenied, // {"code":-4014 ,"msg":"Withdraw is not allowed within 2 min login."} - '-4015': ExchangeError, // {"code":-4015 ,"msg":"Withdraw is limited."} - '-4016': PermissionDenied, // {"code":-4016 ,"msg":"Within 24 hours after password modification, withdrawal is prohibited."} | on swap: {"code":-4016,"msg":"Limit price can't be higher than 27330.52."} - '-4017': PermissionDenied, // {"code":-4017 ,"msg":"Within 24 hours after the release of 2FA, withdrawal is prohibited."} - '-4018': BadSymbol, // {"code":-4018,"msg":"We don't have this asset."} - '-4019': BadSymbol, // {"code":-4019,"msg":"Current asset is not open for withdrawal."} - '-4021': BadRequest, // {"code":-4021,"msg":"Asset withdrawal must be an %s multiple of %s."} - '-4022': BadRequest, // {"code":-4022,"msg":"Not less than the minimum pick-up quantity %s."} - '-4023': ExchangeError, // {"code":-4023,"msg":"Within 24 hours, the withdrawal exceeds the maximum amount."} - '-4024': InsufficientFunds, // {"code":-4024,"msg":"You don't have this asset."} - '-4025': InsufficientFunds, // {"code":-4025,"msg":"The number of hold asset is less than zero."} - '-4026': InsufficientFunds, // {"code":-4026,"msg":"You have insufficient balance."} - '-4027': ExchangeError, // {"code":-4027,"msg":"Failed to obtain tranId."} - '-4028': BadRequest, // {"code":-4028,"msg":"The amount of withdrawal must be greater than the Commission."} - '-4029': BadRequest, // {"code":-4029,"msg":"The withdrawal record does not exist."} - '-4030': ExchangeError, // {"code":-4030,"msg":"Confirmation of successful asset withdrawal. [TODO] possible bug in docs"} - '-4031': ExchangeError, // {"code":-4031,"msg":"Cancellation failed."} - '-4032': ExchangeError, // {"code":-4032,"msg":"Withdraw verification exception."} - '-4033': BadRequest, // {"code":-4033,"msg":"Illegal address."} - '-4034': ExchangeError, // {"code":-4034,"msg":"The address is suspected of fake."} - '-4035': PermissionDenied, // {"code":-4035,"msg":"This address is not on the whitelist. Please join and try again."} - '-4036': BadRequest, // {"code":-4036,"msg":"The new address needs to be withdrawn in {0} hours."} - '-4037': ExchangeError, // {"code":-4037,"msg":"Re-sending Mail failed."} - '-4038': ExchangeError, // {"code":-4038,"msg":"Please try again in 5 minutes."} - '-4039': BadRequest, // {"code":-4039,"msg":"The user does not exist."} - '-4040': BadRequest, // {"code":-4040,"msg":"This address not charged."} - '-4041': ExchangeError, // {"code":-4041,"msg":"Please try again in one minute."} - '-4042': ExchangeError, // {"code":-4042,"msg":"This asset cannot get deposit address again."} - '-4043': BadRequest, // {"code":-4043,"msg":"More than 100 recharge addresses were used in 24 hours."} - '-4044': BadRequest, // {"code":-4044,"msg":"This is a blacklist country."} - '-4045': ExchangeError, // {"code":-4045,"msg":"Failure to acquire assets."} - '-4046': AuthenticationError, // {"code":-4046,"msg":"Agreement not confirmed."} - '-4047': BadRequest, // {"code":-4047,"msg":"Time interval must be within 0-90 days"} - '-4054': BadRequest, // {"code":-4054,"msg":"Cannot add position margin: position is 0."} - '-5001': BadRequest, // {"code":-5001,"msg":"Don't allow transfer to micro assets."} - '-5002': InsufficientFunds, // {"code":-5002,"msg":"You have insufficient balance."} - '-5003': InsufficientFunds, // {"code":-5003,"msg":"You don't have this asset."} - '-5004': BadRequest, // {"code":-5004,"msg":"The residual balances of %s have exceeded 0.001BTC, Please re-choose."} - '-5005': InsufficientFunds, // {"code":-5005,"msg":"The residual balances of %s is too low, Please re-choose."} - '-5006': BadRequest, // {"code":-5006,"msg":"Only transfer once in 24 hours."} - '-5007': BadRequest, // {"code":-5007,"msg":"Quantity must be greater than zero."} - '-5008': InsufficientFunds, // {"code":-5008,"msg":"Insufficient amount of returnable assets."} - '-5009': BadRequest, // {"code":-5009,"msg":"Product does not exist."} - '-5010': ExchangeError, // {"code":-5010,"msg":"Asset transfer fail."} - '-5011': BadRequest, // {"code":-5011,"msg":"future account not exists."} - '-5012': ExchangeError, // {"code":-5012,"msg":"Asset transfer is in pending."} - '-5013': InsufficientFunds, // {"code":-5013,"msg":"Asset transfer failed: insufficient balance""} // undocumented - '-5021': BadRequest, // {"code":-5021,"msg":"This parent sub have no relation"} - '-6001': BadRequest, // {"code":-6001,"msg":"Daily product not exists."} - '-6003': BadRequest, // {"code":-6003,"msg":"Product not exist or you don't have permission"} - '-6004': ExchangeError, // {"code":-6004,"msg":"Product not in purchase status"} - '-6005': InvalidOrder, // {"code":-6005,"msg":"Smaller than min purchase limit"} - '-6006': BadRequest, // {"code":-6006,"msg":"Redeem amount error"} - '-6007': BadRequest, // {"code":-6007,"msg":"Not in redeem time"} - '-6008': BadRequest, // {"code":-6008,"msg":"Product not in redeem status"} - '-6009': RateLimitExceeded, // {"code":-6009,"msg":"Request frequency too high"} - '-6011': BadRequest, // {"code":-6011,"msg":"Exceeding the maximum num allowed to purchase per user"} - '-6012': InsufficientFunds, // {"code":-6012,"msg":"Balance not enough"} - '-6013': ExchangeError, // {"code":-6013,"msg":"Purchasing failed"} - '-6014': BadRequest, // {"code":-6014,"msg":"Exceed up-limit allowed to purchased"} - '-6015': BadRequest, // {"code":-6015,"msg":"Empty request body"} - '-6016': BadRequest, // {"code":-6016,"msg":"Parameter err"} - '-6017': BadRequest, // {"code":-6017,"msg":"Not in whitelist"} - '-6018': BadRequest, // {"code":-6018,"msg":"Asset not enough"} - '-6019': AuthenticationError, // {"code":-6019,"msg":"Need confirm"} - '-6020': BadRequest, // {"code":-6020,"msg":"Project not exists"} - '-7001': BadRequest, // {"code":-7001,"msg":"Date range is not supported."} - '-7002': BadRequest, // {"code":-7002,"msg":"Data request type is not supported."} - '-9000': InsufficientFunds, // {"code":-9000,"msg":"user have no avaliable amount"}" - '-10017': BadRequest, // {"code":-10017,"msg":"Repay amount should not be larger than liability."} - '-11008': InsufficientFunds, // {"code":-11008,"msg":"Exceeding the account's maximum borrowable limit."} // undocumented - '-12014': RateLimitExceeded, // {"code":-12014,"msg":"More than 1 request in 3 seconds"} - '-13000': BadRequest, // {"code":-13000,"msg":"Redeption of the token is forbiden now"} - '-13001': BadRequest, // {"code":-13001,"msg":"Exceeds individual 24h redemption limit of the token"} - '-13002': BadRequest, // {"code":-13002,"msg":"Exceeds total 24h redemption limit of the token"} - '-13003': BadRequest, // {"code":-13003,"msg":"Subscription of the token is forbiden now"} - '-13004': BadRequest, // {"code":-13004,"msg":"Exceeds individual 24h subscription limit of the token"} - '-13005': BadRequest, // {"code":-13005,"msg":"Exceeds total 24h subscription limit of the token"} - '-13006': InvalidOrder, // {"code":-13006,"msg":"Subscription amount is too small"} - '-13007': AuthenticationError, // {"code":-13007,"msg":"The Agreement is not signed"} - '-21001': BadRequest, // {"code":-21001,"msg":"USER_IS_NOT_UNIACCOUNT"} - '-21002': BadRequest, // {"code":-21002,"msg":"UNI_ACCOUNT_CANT_TRANSFER_FUTURE"} - '-21003': BadRequest, // {"code":-21003,"msg":"NET_ASSET_MUST_LTE_RATIO"} - '100001003': AuthenticationError, // {"code":100001003,"msg":"Verification failed"} // undocumented - '200003903': AuthenticationError, // {"code":200003903,"msg":"Your identity verification has been rejected. Please complete identity verification again."} + 'ERR_BAD_REQUEST': BadRequest, + 'ERR_CURRENCY_NOT_FOUND': BadRequest, + 'ERR_DYNAMIC_LINK_CREATION_FAILED': ExchangeError, + 'ERR_CUSTOMER_NOT_FOUND': BadRequest, + 'ERR_BLACKLISTED_ADDRESS': BadRequest, + 'ERR_WITHDRAW_FAILED': ExchangeError, + 'ERR_INVALID_2FA_CODE': AuthenticationError, + 'ERR_INVALID_TOKEN': AuthenticationError, + 'ERR_TOKEN_NOT_FOUND': AuthenticationError, + 'ERR_TOKEN_EXAUSTED': AuthenticationError, + 'ERR_KYC_NOT_APPROVED': AuthenticationError, + 'ERR_INVALID_CURRENCY': BadRequest, + 'ERR_MIN_TRANSFER_AMOUNT': BadRequest, + 'ERR_MAX_TRANSFER_AMOUNT': BadRequest, + 'ERR_IP_NOT_WHITELISTED': AuthenticationError, + 'ERR_LOCKED_WALLET': ExchangeError, + 'ERR_DUPLICATE': ExchangeError, + 'ERR_INSUFFICIENT_BALANCE': BadRequest, + 'ERR_CARD_DECLINED': ExchangeError, + 'ERR_FAILED_PAYMENT': ExchangeError, + 'ERR_CARD_NOT_FOUND': BadRequest, + 'ERR_PAYMENT_ALREADY_PROCESSED': ExchangeError, + 'ERR_DECLINED': ExchangeError, + 'ERR_NOT_FOUND': BadRequest, + 'ERR_INVALID_EMAIL': ExchangeError, + 'ERR_PERMISSION': AuthenticationError, + 'ERR_TX_DISABLED': ExchangeError, + 'ERR_DISABLED_FEATURE': ExchangeError, + 'ERR_TRANSACTION_LIMIT': BadRequest, + 'ERR_MISSING_REQUIREMENT': BadRequest, + 'ERR_ORDER_FAILED': ExchangeError, }, 'broad': { 'has no operation privilege': PermissionDenied, - 'MAX_POSITION': InvalidOrder, // {"code":-2010,"msg":"Filter failure: MAX_POSITION"} + 'MAX_POSITION': InvalidOrder, }, }, }); } - isInverse (type, subType = undefined): boolean { - if (subType === undefined) { - return type === 'delivery'; - } else { - return subType === 'inverse'; - } - } - - isLinear (type, subType = undefined): boolean { - if (subType === undefined) { - return (type === 'future') || (type === 'swap'); - } else { - return subType === 'linear'; - } - } - - setSandboxMode (enable) { - super.setSandboxMode (enable); - this.options['sandboxMode'] = enable; - } - - convertExpireDate (date) { - // parse YYMMDD to timestamp - const year = date.slice (0, 2); - const month = date.slice (2, 4); - const day = date.slice (4, 6); - const reconstructedDate = '20' + year + '-' + month + '-' + day + 'T00:00:00Z'; - return reconstructedDate; - } - - createExpiredOptionMarket (symbol) { - // support expired option contracts - const settle = 'USDT'; - const optionParts = symbol.split ('-'); - const symbolBase = symbol.split ('/'); - let base = undefined; - if (symbol.indexOf ('/') > -1) { - base = this.safeString (symbolBase, 0); - } else { - base = this.safeString (optionParts, 0); - } - const expiry = this.safeString (optionParts, 1); - const strike = this.safeInteger (optionParts, 2); - const strikeAsString = this.safeString (optionParts, 2); - const optionType = this.safeString (optionParts, 3); - const datetime = this.convertExpireDate (expiry); - const timestamp = this.parse8601 (datetime); - return { - 'id': base + '-' + expiry + '-' + strikeAsString + '-' + optionType, - 'symbol': base + '/' + settle + ':' + settle + '-' + expiry + '-' + strikeAsString + '-' + optionType, - 'base': base, - 'quote': settle, - 'baseId': base, - 'quoteId': settle, - 'active': undefined, - 'type': 'option', - 'linear': undefined, - 'inverse': undefined, - 'spot': false, - 'swap': false, - 'future': false, - 'option': true, - 'margin': false, - 'contract': true, - 'contractSize': undefined, - 'expiry': timestamp, - 'expiryDatetime': datetime, - 'optionType': (optionType === 'C') ? 'call' : 'put', - 'strike': strike, - 'settle': settle, - 'settleId': settle, - 'precision': { - 'amount': undefined, - 'price': undefined, - }, - 'limits': { - 'amount': { - 'min': undefined, - 'max': undefined, - }, - 'price': { - 'min': undefined, - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - 'info': undefined, - } as MarketInterface; - } - - market (symbol) { - if (this.markets === undefined) { - throw new ExchangeError (this.id + ' markets not loaded'); - } - // defaultType has legacy support on binance - let defaultType = this.safeString (this.options, 'defaultType'); - const defaultSubType = this.safeString (this.options, 'defaultSubType'); - const isLegacyLinear = defaultType === 'future'; - const isLegacyInverse = defaultType === 'delivery'; - const isLegacy = isLegacyLinear || isLegacyInverse; - if (typeof symbol === 'string') { - if (symbol in this.markets) { - const market = this.markets[symbol]; - // begin diff - if (isLegacy && market['spot']) { - const settle = isLegacyLinear ? market['quote'] : market['base']; - const futuresSymbol = symbol + ':' + settle; - if (futuresSymbol in this.markets) { - return this.markets[futuresSymbol]; - } - } else { - return market; - } - // end diff - } else if (symbol in this.markets_by_id) { - const markets = this.markets_by_id[symbol]; - // begin diff - if (isLegacyLinear) { - defaultType = 'linear'; - } else if (isLegacyInverse) { - defaultType = 'inverse'; - } else if (defaultType === undefined) { - defaultType = defaultSubType; - } - // end diff - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - if (market[defaultType]) { - return market; - } - } - return markets[0]; - } else if ((symbol.indexOf ('/') > -1) && (symbol.indexOf (':') < 0)) { - // support legacy symbols - const [ base, quote ] = symbol.split ('/'); - const settle = (quote === 'USD') ? base : quote; - const futuresSymbol = symbol + ':' + settle; - if (futuresSymbol in this.markets) { - return this.markets[futuresSymbol]; - } - } else if ((symbol.indexOf ('-C') > -1) || (symbol.indexOf ('-P') > -1)) { // both exchange-id and unified symbols are supported this way regardless of the defaultType - return this.createExpiredOptionMarket (symbol); - } - } - throw new BadSymbol (this.id + ' does not have market symbol ' + symbol); - } - - safeMarket (marketId = undefined, market = undefined, delimiter = undefined, marketType = undefined) { - const isOption = (marketId !== undefined) && ((marketId.indexOf ('-C') > -1) || (marketId.indexOf ('-P') > -1)); - if (isOption && !(marketId in this.markets_by_id)) { - // handle expired option contracts - return this.createExpiredOptionMarket (marketId); - } - return super.safeMarket (marketId, market, delimiter, marketType); - } - - costToPrecision (symbol, cost) { - return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['quote'], this.precisionMode, this.paddingMode); - } - - currencyToPrecision (code, fee, networkCode = undefined) { - // info is available in currencies only if the user has configured his api keys - if (this.safeValue (this.currencies[code], 'precision') !== undefined) { - return this.decimalToPrecision (fee, TRUNCATE, this.currencies[code]['precision'], this.precisionMode, this.paddingMode); - } else { - return this.numberToString (fee); - } - } - - nonce () { - return this.milliseconds () - this.options['timeDifference']; - } - async fetchTime (params = {}) { /** * @method - * @name binance#fetchTime + * @name youngplatform#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server - * @see https://binance-docs.github.io/apidocs/spot/en/#check-server-time // spot - * @see https://binance-docs.github.io/apidocs/futures/en/#check-server-time // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#check-server-time // future * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ - const defaultType = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot'); - const type = this.safeString (params, 'type', defaultType); - const query = this.omit (params, 'type'); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchTime', undefined, params); - let response = undefined; - if (this.isLinear (type, subType)) { - response = await this.fapiPublicGetTime (query); - } else if (this.isInverse (type, subType)) { - response = await this.dapiPublicGetTime (query); - } else { - response = await this.publicGetTime (query); - } - return this.safeInteger (response, 'serverTime'); + const response = await this.v4PublicGetTime (params); + // + // { + // "time": "2024-01-01T01:01:01Z" + // } + // + return this.safeTimestamp (response, 'time'); } async fetchCurrencies (params = {}) { /** * @method - * @name binance#fetchCurrencies + * @name youngplatform#fetchCurrencies * @description fetches all available currencies on an exchange - * @see https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an associative dictionary of currencies */ - const fetchCurrenciesEnabled = this.safeValue (this.options, 'fetchCurrencies'); - if (!fetchCurrenciesEnabled) { - return undefined; - } - // this endpoint requires authentication - // while fetchCurrencies is a public API method by design - // therefore we check the keys here - // and fallback to generating the currencies from the markets - if (!this.checkRequiredCredentials (false)) { - return undefined; - } - // sandbox/testnet does not support sapi endpoints - const apiBackup = this.safeValue (this.urls, 'apiBackup'); - if (apiBackup !== undefined) { - return undefined; - } - const response = await this.sapiGetCapitalConfigGetall (params); + const response = await this.v4PublicGetCurrencies (params); + // + // [ + // { + // "name": "AAVE", + // "symbol": "AAVE", + // "decimalPrecision": 18, + // "price": 59.75, + // "priority": 0, + // "details": + // { + // "color": "#a361a4", + // "image": "https://images.youngplatform.com/coins/aave_light_3.png", + // "imageLight": "https://images.youngplatform.com/coins/aave_light_3.png", + // "imageWalletCover": null, + // "imageWalletCoverLandscapeMobile": null, + // "imageWalletCoverLandscapeDesktop": null, + // "maxSupply": 0, + // "circulatingSupply": 16000000, + // "volume24h": 66377777.09200996, + // "marketCap": 1454533970.760525, + // "priceChange24h": 2.6188285841196692, + // "webSite": "https://aave.com", + // "whitePaper": "https://github.com/aave/aave-protocol/blob/master/docs/Aave_Protocol_Whitepaper_v1_0.pdf", + // "mineable": false, + // "creationDate": "1970-01-01T00:00:00Z" + // }, + // "networks": null, + // "tags": + // [ + // { + // "id": 3, + // "label": "platform_pro", + // "description": "pro", + // "priority": 0, + // "isManual": true + // }, + // { + // "id": 4, + // "label": "category", + // "description": "DeFi", + // "priority": 0, + // "isManual": true + // } + // ], + // "descriptions": + // { + // "en": "Aave is a decentralised financial protocol that allows people to lend and borrow crypto. AAVE has several strengths that make it unique in the DeFi landscape. Its protocol supports around 20 cryptocurrencies, it created the first uncollateralised loans known as \"flash loans.\" It allows users to choose between fixed and variable interest rates.", + // "fr": "L'Aave est un protocole financier décentralisé qui permet aux particuliers de prêter et d'emprunter des cryptomonnaies. L'AAVE présente plusieurs atouts qui le rendent unique dans le paysage DeFi. Son protocole propose une vingtaine de cryptomonnaies, il a inventé les « prêts flash » sans garantie, et il permet de choisir entre des taux d'intérêt fixes et variables.", + // "it": "Aave è un protocollo finanziario decentralizzato che permette alle persone di prestare e prendere in prestito crypto. AAVE ha diversi punti di forza che la rendono unica nel panorama DeFi. Offre circa 20 criptovalute, ha inventato i “prestiti flash” e consente di alternare tassi di interesse fissi e variabili." + // } + // } + // ] + // const result = {}; for (let i = 0; i < response.length; i++) { - // - // { - // "coin": "LINK", - // "depositAllEnable": true, - // "withdrawAllEnable": true, - // "name": "ChainLink", - // "free": "0", - // "locked": "0", - // "freeze": "0", - // "withdrawing": "0", - // "ipoing": "0", - // "ipoable": "0", - // "storage": "0", - // "isLegalMoney": false, - // "trading": true, - // "networkList": [ - // { - // "network": "BSC", - // "coin": "LINK", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": false, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": "", - // "withdrawDesc": "", - // "specialTips": "", - // "specialWithdrawTips": "The network you have selected is BSC. Please ensure that the withdrawal address supports the Binance Smart Chain network. You will lose your assets if the chosen platform does not support retrievals.", - // "name": "BNB Smart Chain (BEP20)", - // "resetAddressStatus": false, - // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", - // "addressRule": "", - // "memoRegex": "", - // "withdrawFee": "0.012", - // "withdrawMin": "0.024", - // "withdrawMax": "9999999999.99999999", - // "minConfirm": "15", - // "unLockConfirm": "0", - // "sameAddress": false, - // "estimatedArrivalTime": "5", - // "busy": false, - // "country": "AE,BINANCE_BAHRAIN_BSC" - // }, - // { - // "network": "BNB", - // "coin": "LINK", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": false, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": "", - // "withdrawDesc": "", - // "specialTips": "Both a MEMO and an Address are required to successfully deposit your LINK BEP2 tokens to Binance.", - // "specialWithdrawTips": "", - // "name": "BNB Beacon Chain (BEP2)", - // "resetAddressStatus": false, - // "addressRegex": "^(bnb1)[0-9a-z]{38}$", - // "addressRule": "", - // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", - // "withdrawFee": "0.002", - // "withdrawMin": "0.01", - // "withdrawMax": "10000000000", - // "minConfirm": "1", - // "unLockConfirm": "0", - // "sameAddress": true, - // "estimatedArrivalTime": "5", - // "busy": false, - // "country": "AE,BINANCE_BAHRAIN_BSC" - // }, - // { - // "network": "ETH", - // "coin": "LINK", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": true, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": "", - // "withdrawDesc": "", - // "name": "Ethereum (ERC20)", - // "resetAddressStatus": false, - // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", - // "addressRule": "", - // "memoRegex": "", - // "withdrawFee": "0.55", - // "withdrawMin": "1.1", - // "withdrawMax": "10000000000", - // "minConfirm": "12", - // "unLockConfirm": "0", - // "sameAddress": false, - // "estimatedArrivalTime": "5", - // "busy": false, - // "country": "AE,BINANCE_BAHRAIN_BSC" - // } - // ] - // } - // - const entry = response[i]; - const id = this.safeString (entry, 'coin'); - const name = this.safeString (entry, 'name'); + const currency = response[i]; + const id = this.safeString (currency, 'symbol'); + const name = this.safeString (currency, 'name'); const code = this.safeCurrencyCode (id); - let minPrecision = undefined; - let isWithdrawEnabled = true; - let isDepositEnabled = true; - const networkList = this.safeValue (entry, 'networkList', []); - const fees = {}; - let fee = undefined; - for (let j = 0; j < networkList.length; j++) { - const networkItem = networkList[j]; - const network = this.safeString (networkItem, 'network'); - // const name = this.safeString (networkItem, 'name'); - const withdrawFee = this.safeNumber (networkItem, 'withdrawFee'); - const depositEnable = this.safeValue (networkItem, 'depositEnable'); - const withdrawEnable = this.safeValue (networkItem, 'withdrawEnable'); - isDepositEnabled = isDepositEnabled || depositEnable; - isWithdrawEnabled = isWithdrawEnabled || withdrawEnable; - fees[network] = withdrawFee; - const isDefault = this.safeValue (networkItem, 'isDefault'); - if (isDefault || (fee === undefined)) { - fee = withdrawFee; - } - const precisionTick = this.safeString (networkItem, 'withdrawIntegerMultiple'); - // avoid zero values, which are mostly from fiat or leveraged tokens : https://github.com/ccxt/ccxt/pull/14902#issuecomment-1271636731 - // so, when there is zero instead of i.e. 0.001, then we skip those cases, because we don't know the precision - it might be because of network is suspended or other reasons - if (!Precise.stringEq (precisionTick, '0')) { - minPrecision = (minPrecision === undefined) ? precisionTick : Precise.stringMin (minPrecision, precisionTick); - } - } - const trading = this.safeValue (entry, 'trading'); - const active = (isWithdrawEnabled && isDepositEnabled && trading); - let maxDecimalPlaces = undefined; - if (minPrecision !== undefined) { - maxDecimalPlaces = parseInt (this.numberToString (this.precisionFromString (minPrecision))); - } + const networks = this.safeValue (currency, 'networks', {}); result[code] = { 'id': id, - 'name': name, 'code': code, - 'precision': maxDecimalPlaces, - 'info': entry, - 'active': active, - 'deposit': isDepositEnabled, - 'withdraw': isWithdrawEnabled, - 'networks': networkList, - 'fee': fee, - 'fees': fees, - 'limits': this.limits, + 'info': currency, + 'type': (id === 'EUR' || id === 'USD') ? 'fiat' : 'crypto', + 'name': name, + 'active': true, + 'deposit': undefined, + 'withdraw': undefined, + 'fee': undefined, + 'precision': this.safeNumber (currency, 'max_precision'), + 'limits': { + 'amount': { + 'min': undefined, + 'max': undefined, + }, + 'withdraw': { + 'min': undefined, + 'max': undefined, + }, + }, + 'networks': networks, }; } return result; @@ -2016,7512 +372,587 @@ export default class youngplatform extends Exchange { async fetchMarkets (params = {}) { /** * @method - * @name binance#fetchMarkets - * @description retrieves data on all markets for binance - * @see https://binance-docs.github.io/apidocs/spot/en/#exchange-information // spot - * @see https://binance-docs.github.io/apidocs/futures/en/#exchange-information // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#exchange-information // future - * @see https://binance-docs.github.io/apidocs/voptions/en/#exchange-information // option + * @name youngplatform#fetchMarkets + * @description retrieves data on all markets for an exchange * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ - const promisesRaw = []; - const rawFetchMarkets = this.safeValue (this.options, 'fetchMarkets', [ 'spot', 'linear', 'inverse' ]); - const sandboxMode = this.safeValue (this.options, 'sandboxMode', false); - const fetchMarkets = []; - for (let i = 0; i < rawFetchMarkets.length; i++) { - const type = rawFetchMarkets[i]; - if (type === 'option' && sandboxMode) { - continue; - } - fetchMarkets.push (type); - } - for (let i = 0; i < fetchMarkets.length; i++) { - const marketType = fetchMarkets[i]; - if (marketType === 'spot') { - promisesRaw.push (this.publicGetExchangeInfo (params)); - } else if (marketType === 'linear') { - promisesRaw.push (this.fapiPublicGetExchangeInfo (params)); - } else if (marketType === 'inverse') { - promisesRaw.push (this.dapiPublicGetExchangeInfo (params)); - } else if (marketType === 'option') { - promisesRaw.push (this.eapiPublicGetExchangeInfo (params)); - } else { - throw new ExchangeError (this.id + ' fetchMarkets() this.options fetchMarkets "' + marketType + '" is not a supported market type'); - } - } - const promises = await Promise.all (promisesRaw); - const spotMarkets = this.safeValue (this.safeValue (promises, 0), 'symbols', []); - const futureMarkets = this.safeValue (this.safeValue (promises, 1), 'symbols', []); - const deliveryMarkets = this.safeValue (this.safeValue (promises, 2), 'symbols', []); - const optionMarkets = this.safeValue (this.safeValue (promises, 3), 'optionSymbols', []); - let markets = spotMarkets; - markets = this.arrayConcat (markets, futureMarkets); - markets = this.arrayConcat (markets, deliveryMarkets); - markets = this.arrayConcat (markets, optionMarkets); - // - // spot / margin - // - // { - // "timezone":"UTC", - // "serverTime":1575416692969, - // "rateLimits":[ - // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200}, - // {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":100}, - // {"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":200000} - // ], - // "exchangeFilters":[], - // "symbols":[ - // { - // "symbol":"ETHBTC", - // "status":"TRADING", - // "baseAsset":"ETH", - // "baseAssetPrecision":8, - // "quoteAsset":"BTC", - // "quotePrecision":8, - // "baseCommissionPrecision":8, - // "quoteCommissionPrecision":8, - // "orderTypes":["LIMIT","LIMIT_MAKER","MARKET","STOP_LOSS_LIMIT","TAKE_PROFIT_LIMIT"], - // "icebergAllowed":true, - // "ocoAllowed":true, - // "quoteOrderQtyMarketAllowed":true, - // "allowTrailingStop":false, - // "isSpotTradingAllowed":true, - // "isMarginTradingAllowed":true, - // "filters":[ - // {"filterType":"PRICE_FILTER","minPrice":"0.00000100","maxPrice":"100000.00000000","tickSize":"0.00000100"}, - // {"filterType":"PERCENT_PRICE","multiplierUp":"5","multiplierDown":"0.2","avgPriceMins":5}, - // {"filterType":"LOT_SIZE","minQty":"0.00100000","maxQty":"100000.00000000","stepSize":"0.00100000"}, - // {"filterType":"MIN_NOTIONAL","minNotional":"0.00010000","applyToMarket":true,"avgPriceMins":5}, - // {"filterType":"ICEBERG_PARTS","limit":10}, - // {"filterType":"MARKET_LOT_SIZE","minQty":"0.00000000","maxQty":"63100.00000000","stepSize":"0.00000000"}, - // {"filterType":"MAX_NUM_ORDERS","maxNumOrders":200}, - // {"filterType":"MAX_NUM_ALGO_ORDERS","maxNumAlgoOrders":5} - // ], - // "permissions":["SPOT","MARGIN"]} - // }, - // ], - // } - // - // futures/usdt-margined (fapi) - // - // { - // "timezone":"UTC", - // "serverTime":1575417244353, - // "rateLimits":[ - // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200}, - // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":1200} - // ], - // "exchangeFilters":[], - // "symbols":[ - // { - // "symbol":"BTCUSDT", - // "status":"TRADING", - // "maintMarginPercent":"2.5000", - // "requiredMarginPercent":"5.0000", - // "baseAsset":"BTC", - // "quoteAsset":"USDT", - // "pricePrecision":2, - // "quantityPrecision":3, - // "baseAssetPrecision":8, - // "quotePrecision":8, - // "filters":[ - // {"minPrice":"0.01","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.01"}, - // {"stepSize":"0.001","filterType":"LOT_SIZE","maxQty":"1000","minQty":"0.001"}, - // {"stepSize":"0.001","filterType":"MARKET_LOT_SIZE","maxQty":"1000","minQty":"0.001"}, - // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, - // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} - // ], - // "orderTypes":["LIMIT","MARKET","STOP"], - // "timeInForce":["GTC","IOC","FOK","GTX"] - // } - // ] - // } - // - // delivery/coin-margined (dapi) - // - // { - // "timezone": "UTC", - // "serverTime": 1597667052958, - // "rateLimits": [ - // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000}, - // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":6000} - // ], - // "exchangeFilters": [], - // "symbols": [ - // { - // "symbol": "BTCUSD_200925", - // "pair": "BTCUSD", - // "contractType": "CURRENT_QUARTER", - // "deliveryDate": 1601020800000, - // "onboardDate": 1590739200000, - // "contractStatus": "TRADING", - // "contractSize": 100, - // "marginAsset": "BTC", - // "maintMarginPercent": "2.5000", - // "requiredMarginPercent": "5.0000", - // "baseAsset": "BTC", - // "quoteAsset": "USD", - // "pricePrecision": 1, - // "quantityPrecision": 0, - // "baseAssetPrecision": 8, - // "quotePrecision": 8, - // "equalQtyPrecision": 4, - // "filters": [ - // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"}, - // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"}, - // {"stepSize":"0","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"}, - // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, - // {"multiplierDown":"0.9500","multiplierUp":"1.0500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} - // ], - // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"], - // "timeInForce": ["GTC","IOC","FOK","GTX"] - // }, - // { - // "symbol": "BTCUSD_PERP", - // "pair": "BTCUSD", - // "contractType": "PERPETUAL", - // "deliveryDate": 4133404800000, - // "onboardDate": 1596006000000, - // "contractStatus": "TRADING", - // "contractSize": 100, - // "marginAsset": "BTC", - // "maintMarginPercent": "2.5000", - // "requiredMarginPercent": "5.0000", - // "baseAsset": "BTC", - // "quoteAsset": "USD", - // "pricePrecision": 1, - // "quantityPrecision": 0, - // "baseAssetPrecision": 8, - // "quotePrecision": 8, - // "equalQtyPrecision": 4, - // "filters": [ - // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"}, - // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"}, - // {"stepSize":"1","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"}, - // {"limit":200,"filterType":"MAX_NUM_ORDERS"}, - // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"} - // ], - // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"], - // "timeInForce": ["GTC","IOC","FOK","GTX"] - // } - // ] - // } - // - // options (eapi) - // + const response = await this.v4PublicGetMarkets (params); + // [ // { - // "timezone": "UTC", - // "serverTime": 1675912490405, - // "optionContracts": [ - // { - // "id": 1, - // "baseAsset": "SOL", - // "quoteAsset": "USDT", - // "underlying": "SOLUSDT", - // "settleAsset": "USDT" - // }, - // ... - // ], - // "optionAssets": [ - // {"id":1,"name":"USDT"} - // ], - // "optionSymbols": [ - // { - // "contractId": 3, - // "expiryDate": 1677225600000, - // "filters": [ - // {"filterType":"PRICE_FILTER","minPrice":"724.6","maxPrice":"919.2","tickSize":"0.1"}, - // {"filterType":"LOT_SIZE","minQty":"0.01","maxQty":"1000","stepSize":"0.01"} - // ], - // "id": 2474, - // "symbol": "ETH-230224-800-C", - // "side": "CALL", - // "strikePrice": "800.00000000", - // "underlying": "ETHUSDT", - // "unit": 1, - // "makerFeeRate": "0.00020000", - // "takerFeeRate": "0.00020000", - // "minQty": "0.01", - // "maxQty": "1000", - // "initialMargin": "0.15000000", - // "maintenanceMargin": "0.07500000", - // "minInitialMargin": "0.10000000", - // "minMaintenanceMargin": "0.05000000", - // "priceScale": 1, - // "quantityScale": 2, - // "quoteAsset": "USDT" - // }, - // ... - // ], - // "rateLimits": [ - // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":400}, - // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":100}, - // {"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":30} - // ] - // } - // - if (this.options['adjustForTimeDifference']) { - await this.loadTimeDifference (); - } + // "id": 1, + // "name": "XRP-EUR", + // "base": "XRP", + // "quote": "EUR", + // "minTradeAmount": 1e-8, + // "makerFee": 0.2, + // "takerFee": 0.2, + // "makerFeeBase": 2.5, + // "takerFeeBase": 3.375, + // "baseDecimalPrecision": 0, + // "quoteDecimalPrecision": 0, + // "minTickSize": 0.00001, + // "minOrderValue": 9.9, + // "active": true, + // "activeMarginTrading": false, + // "visible": true, + // "fixedFeeTiers": [] + // } + // ] const result = []; - for (let i = 0; i < markets.length; i++) { - result.push (this.parseMarket (markets[i])); + for (let i = 0; i < response.length; i++) { + const market = response[i]; + const id = this.safeString (market, 'id'); + const baseId = this.safeString (market, 'base'); + const quoteId = this.safeString (market, 'quote'); + const base = this.safeCurrencyCode (baseId); + const quote = this.safeCurrencyCode (quoteId); + const marketType = 'spot'; + const tradingDisabled = this.safeValue (market, 'visible'); + result[i] = ({ + 'id': id, + 'symbol': base + '/' + quote, + 'base': base, + 'quote': quote, + 'settle': undefined, + 'baseId': baseId, + 'quoteId': quoteId, + 'settleId': undefined, + 'type': marketType, + 'spot': (marketType === 'spot'), + 'margin': undefined, + 'swap': false, + 'future': false, + 'option': false, + 'active': !tradingDisabled, + 'contract': false, + 'linear': undefined, + 'inverse': undefined, + 'taker': this.safeNumber (market, 'takerFeeBase'), + 'maker': this.safeNumber (market, 'makerFee'), + 'contractSize': undefined, + 'expiry': undefined, + 'expiryDatetime': undefined, + 'strike': undefined, + 'optionType': undefined, + 'precision': { + 'amount': this.safeNumber (market, 'minTickSize'), + 'price': this.safeNumber (market, 'minTickSize'), + }, + 'limits': { + 'leverage': { + 'min': undefined, + 'max': undefined, + }, + 'amount': { + 'min': this.safeNumber (market, 'minTradeAmount'), + 'max': undefined, + }, + 'price': { + 'min': undefined, + 'max': undefined, + }, + 'cost': { + 'min': this.safeNumber (market, 'minOrderValue'), + 'max': undefined, + }, + }, + 'created': undefined, + 'info': market, + }); } return result; } - parseMarket (market): Market { - let swap = false; - let future = false; - let option = false; - const underlying = this.safeString (market, 'underlying'); - const id = this.safeString (market, 'symbol'); - const optionParts = id.split ('-'); - const optionBase = this.safeString (optionParts, 0); - const lowercaseId = this.safeStringLower (market, 'symbol'); - const baseId = this.safeString (market, 'baseAsset', optionBase); - const quoteId = this.safeString (market, 'quoteAsset'); - const base = this.safeCurrencyCode (baseId); - const quote = this.safeCurrencyCode (quoteId); - const contractType = this.safeString (market, 'contractType'); - let contract = ('contractType' in market); - let expiry = this.safeInteger2 (market, 'deliveryDate', 'expiryDate'); - let settleId = this.safeString (market, 'marginAsset'); - if ((contractType === 'PERPETUAL') || (expiry === 4133404800000)) { // some swap markets do not have contract type, eg: BTCST - expiry = undefined; - swap = true; - } else if (underlying !== undefined) { - contract = true; - option = true; - settleId = (settleId === undefined) ? 'USDT' : settleId; - } else if (expiry !== undefined) { - future = true; - } - const settle = this.safeCurrencyCode (settleId); - const spot = !contract; - const filters = this.safeValue (market, 'filters', []); - const filtersByType = this.indexBy (filters, 'filterType'); - const status = this.safeString2 (market, 'status', 'contractStatus'); - let contractSize = undefined; - let fees = this.fees; - let linear = undefined; - let inverse = undefined; - const strike = this.safeInteger (market, 'strikePrice'); - let symbol = base + '/' + quote; - if (contract) { - if (swap) { - symbol = symbol + ':' + settle; - } else if (future) { - symbol = symbol + ':' + settle + '-' + this.yymmdd (expiry); - } else if (option) { - symbol = symbol + ':' + settle + '-' + this.yymmdd (expiry) + '-' + this.numberToString (strike) + '-' + this.safeString (optionParts, 3); - } - contractSize = this.safeNumber2 (market, 'contractSize', 'unit', this.parseNumber ('1')); - linear = settle === quote; - inverse = settle === base; - const feesType = linear ? 'linear' : 'inverse'; - fees = this.safeValue (this.fees, feesType, {}); - } - let active = (status === 'TRADING'); - if (spot) { - const permissions = this.safeValue (market, 'permissions', []); - for (let j = 0; j < permissions.length; j++) { - if (permissions[j] === 'TRD_GRP_003') { - active = false; - break; - } - } - } - const isMarginTradingAllowed = this.safeValue (market, 'isMarginTradingAllowed', false); - let unifiedType = undefined; - if (spot) { - unifiedType = 'spot'; - } else if (swap) { - unifiedType = 'swap'; - } else if (future) { - unifiedType = 'future'; - } else if (option) { - unifiedType = 'option'; - active = undefined; - } - const entry = { - 'id': id, - 'lowercaseId': lowercaseId, - 'symbol': symbol, - 'base': base, - 'quote': quote, - 'settle': settle, - 'baseId': baseId, - 'quoteId': quoteId, - 'settleId': settleId, - 'type': unifiedType, - 'spot': spot, - 'margin': spot && isMarginTradingAllowed, - 'swap': swap, - 'future': future, - 'option': option, - 'active': active, - 'contract': contract, - 'linear': linear, - 'inverse': inverse, - 'taker': fees['trading']['taker'], - 'maker': fees['trading']['maker'], - 'contractSize': contractSize, - 'expiry': expiry, - 'expiryDatetime': this.iso8601 (expiry), - 'strike': strike, - 'optionType': this.safeStringLower (market, 'side'), - 'precision': { - 'amount': this.safeInteger2 (market, 'quantityPrecision', 'quantityScale'), - 'price': this.safeInteger2 (market, 'pricePrecision', 'priceScale'), - 'base': this.safeInteger (market, 'baseAssetPrecision'), - 'quote': this.safeInteger (market, 'quotePrecision'), - }, - 'limits': { - 'leverage': { - 'min': undefined, - 'max': undefined, - }, - 'amount': { - 'min': this.safeNumber (market, 'minQty'), - 'max': this.safeNumber (market, 'maxQty'), - }, - 'price': { - 'min': undefined, - 'max': undefined, - }, - 'cost': { - 'min': undefined, - 'max': undefined, - }, - }, - 'info': market, - 'created': this.safeInteger (market, 'onboardDate'), // present in inverse & linear apis - }; - if ('PRICE_FILTER' in filtersByType) { - const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {}); - // PRICE_FILTER reports zero values for maxPrice - // since they updated filter types in November 2018 - // https://github.com/ccxt/ccxt/issues/4286 - // therefore limits['price']['max'] doesn't have any meaningful value except undefined - entry['limits']['price'] = { - 'min': this.safeNumber (filter, 'minPrice'), - 'max': this.safeNumber (filter, 'maxPrice'), - }; - entry['precision']['price'] = this.precisionFromString (filter['tickSize']); - } - if ('LOT_SIZE' in filtersByType) { - const filter = this.safeValue (filtersByType, 'LOT_SIZE', {}); - const stepSize = this.safeString (filter, 'stepSize'); - entry['precision']['amount'] = this.precisionFromString (stepSize); - entry['limits']['amount'] = { - 'min': this.safeNumber (filter, 'minQty'), - 'max': this.safeNumber (filter, 'maxQty'), - }; - } - if ('MARKET_LOT_SIZE' in filtersByType) { - const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {}); - entry['limits']['market'] = { - 'min': this.safeNumber (filter, 'minQty'), - 'max': this.safeNumber (filter, 'maxQty'), - }; - } - if (('MIN_NOTIONAL' in filtersByType) || ('NOTIONAL' in filtersByType)) { // notional added in 12/04/23 to spot testnet - const filter = this.safeValue2 (filtersByType, 'MIN_NOTIONAL', 'NOTIONAL', {}); - entry['limits']['cost']['min'] = this.safeNumber2 (filter, 'minNotional', 'notional'); - entry['limits']['cost']['max'] = this.safeNumber (filter, 'maxNotional'); - } - return entry; + async fetchTicker (symbol: string, params = {}): Promise { + /** + * @method + * @name youngplatform#fetchTicker + * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market + * @param {string} symbol unified symbol of the market to fetch the ticker for + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const response = await this.v4PublicGetTicker (params); + // { + // "pair": "ETH-EUR", + // "open": 3357.73, + // "high": 3416.4, + // "low": 3130.87, + // "close": 3223.1, + // "bid": 0, + // "ask": 0, + // "percentChange": -4.00955407, + // "baseVolume": 604346.84676924, + // "quoteVolume": 183.49, + // "baseVolume24h": 0, + // "quoteVolume24h": 0, + // "timestamp": 1707144193779 + // } + const bid = this.safeNumber (response, 'bid'); + const ask = this.safeNumber (response, 'ask'); + const bidVolume = this.safeNumber (response, 'baseVolume'); + const askVolume = this.safeNumber (response, 'quoteVolume'); + const marketId = this.safeString (response, 'pair'); + const last = this.safeNumber (response, 'close'); + const timestamp = this.safeNumber (response, 'timestamp'); + const timestampString = this.numberToString (timestamp); + return ({ + 'symbol': this.safeSymbol (marketId, market), + 'timestamp': timestampString, + 'datetime': timestampString, + 'bid': bid, + 'ask': ask, + 'last': last, + 'high': undefined, + 'low': undefined, + 'bidVolume': bidVolume, + 'askVolume': askVolume, + 'vwap': undefined, + 'open': undefined, + 'close': last, + 'previousClose': undefined, + 'change': undefined, + 'percentage': this.safeNumber (response, 'price_percentage_change_24h'), + 'average': undefined, + 'baseVolume': undefined, + 'quoteVolume': undefined, + 'info': response, + }); } - parseBalanceHelper (entry) { - const account = this.account (); - account['used'] = this.safeString (entry, 'locked'); - account['free'] = this.safeString (entry, 'free'); - const interest = this.safeString (entry, 'interest'); - const debt = this.safeString (entry, 'borrowed'); - account['debt'] = Precise.stringAdd (debt, interest); - return account; + async fetchTrades (symbol: string, since: Int = undefined, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name youngplatform#fetchTrades + * @description get the list of most recent trades for a particular symbol + * @param {string} symbol unified market symbol of the trades + * @param {int} [since] not used by youngplatform fetchTrades + * @param {int} [limit] the maximum number of trade structures to fetch + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} + */ + await this.loadMarkets (); + const market = this.market (symbol); + const response = await this.v4PublicGetTicker (params); + // [ + // { + // "id": 123456, + // "orderId": 789012, + // "baseCurrency": "USD", + // "quoteCurrency": "BTC", + // "side": "Buy", + // "taker": true, + // "amount": 10.25, + // "volume": 0.002, + // "rate": 50000.75, + // "brokerage": 0.0025, + // "brokerageCurrency": "USD", + // "executionDate": "2024-02-05T14:30:00" + // } + // ] + return this.parseTrades (response, market, since, limit); } - parseBalance (response, type = undefined, marginMode = undefined): Balances { - const result = { - 'info': response, + async fetchOrderBook (symbol: string, limit: Int = undefined, params = {}): Promise { + /** + * @method + * @name youngplatform#fetchOrderBook + * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data + * @param {string} symbol unified symbol of the market to fetch the order book for + * @param {int} [limit] the maximum amount of order book entries to return + * @param {object} [params] extra parameters specific to the exchange API endpoint + * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols + */ + await this.loadMarkets (); + const market = this.market (symbol); + const request = { + 'pair': market['id'], }; - let timestamp = undefined; - const isolated = marginMode === 'isolated'; - const cross = (type === 'margin') || (marginMode === 'cross'); - if (!isolated && ((type === 'spot') || cross)) { - timestamp = this.safeInteger (response, 'updateTime'); - const balances = this.safeValue2 (response, 'balances', 'userAssets', []); - for (let i = 0; i < balances.length; i++) { - const balance = balances[i]; - const currencyId = this.safeString (balance, 'asset'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['free'] = this.safeString (balance, 'free'); - account['used'] = this.safeString (balance, 'locked'); - if (cross) { - const debt = this.safeString (balance, 'borrowed'); - const interest = this.safeString (balance, 'interest'); - account['debt'] = Precise.stringAdd (debt, interest); - } - result[code] = account; - } - } else if (isolated) { - const assets = this.safeValue (response, 'assets'); - for (let i = 0; i < assets.length; i++) { - const asset = assets[i]; - const marketId = this.safeValue (asset, 'symbol'); - const symbol = this.safeSymbol (marketId, undefined, undefined, 'spot'); - const base = this.safeValue (asset, 'baseAsset', {}); - const quote = this.safeValue (asset, 'quoteAsset', {}); - const baseCode = this.safeCurrencyCode (this.safeString (base, 'asset')); - const quoteCode = this.safeCurrencyCode (this.safeString (quote, 'asset')); - const subResult = {}; - subResult[baseCode] = this.parseBalanceHelper (base); - subResult[quoteCode] = this.parseBalanceHelper (quote); - result[symbol] = this.safeBalance (subResult); - } - } else if (type === 'savings') { - const positionAmountVos = this.safeValue (response, 'positionAmountVos', []); - for (let i = 0; i < positionAmountVos.length; i++) { - const entry = positionAmountVos[i]; - const currencyId = this.safeString (entry, 'asset'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - const usedAndTotal = this.safeString (entry, 'amount'); - account['total'] = usedAndTotal; - account['used'] = usedAndTotal; - result[code] = account; - } - } else if (type === 'funding') { - for (let i = 0; i < response.length; i++) { - const entry = response[i]; - const account = this.account (); - const currencyId = this.safeString (entry, 'asset'); - const code = this.safeCurrencyCode (currencyId); - account['free'] = this.safeString (entry, 'free'); - const frozen = this.safeString (entry, 'freeze'); - const withdrawing = this.safeString (entry, 'withdrawing'); - const locked = this.safeString (entry, 'locked'); - account['used'] = Precise.stringAdd (frozen, Precise.stringAdd (locked, withdrawing)); - result[code] = account; - } - } else { - let balances = response; - if (!Array.isArray (response)) { - balances = this.safeValue (response, 'assets', []); - } - for (let i = 0; i < balances.length; i++) { - const balance = balances[i]; - const currencyId = this.safeString (balance, 'asset'); - const code = this.safeCurrencyCode (currencyId); - const account = this.account (); - account['free'] = this.safeString (balance, 'availableBalance'); - account['used'] = this.safeString (balance, 'initialMargin'); - account['total'] = this.safeString2 (balance, 'marginBalance', 'balance'); - result[code] = account; - } + if (limit !== undefined) { + request['depth'] = limit; } - result['timestamp'] = timestamp; - result['datetime'] = this.iso8601 (timestamp); - return isolated ? result : this.safeBalance (result); + const response = await this.v4PublicGetOrderbook (this.extend (request, params)); + // { + // "ticker_id": "BTC-EUR", + // "timestamp": "2024-02-14T14:55:40.286Z", + // "bids": [ + // { + // "price": "48284.08000000", + // "size": "0.00792000" + // }, + // { + // "price": "48280.64000000", + // "size": "0.00041000" + // } + // ], + // "asks": [ + // { + // "price": "48440.86000000", + // "size": "0.01101000" + // }, + // { + // "price": "48443.75000000", + // "size": "0.00041000" + // } + // ] + // } + const time = this.safeString (response, 'timestamp'); + const timestamp = this.parse8601 (time); + return this.parseOrderBook (response, symbol, timestamp, 'bids', 'asks', 'price', 'size'); } async fetchBalance (params = {}): Promise { /** * @method - * @name binance#fetchBalance + * @name youngplatform#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders - * @see https://binance-docs.github.io/apidocs/spot/en/#account-information-user_data // spot - * @see https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-account-details-user_data // cross margin - * @see https://binance-docs.github.io/apidocs/spot/en/#query-isolated-margin-account-info-user_data // isolated margin - * @see https://binance-docs.github.io/apidocs/spot/en/#lending-account-user_data // lending - * @see https://binance-docs.github.io/apidocs/spot/en/#funding-wallet-user_data // funding - * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data // future - * @see https://binance-docs.github.io/apidocs/voptions/en/#option-account-information-trade // option * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.type] 'future', 'delivery', 'savings', 'funding', or 'spot' - * @param {string} [params.marginMode] 'cross' or 'isolated', for margin trading, uses this.options.defaultMarginMode if not passed, defaults to undefined/None/null - * @param {string[]|undefined} [params.symbols] unified market symbols, only used in isolated margin mode * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ await this.loadMarkets (); - const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot'); - let type = this.safeString (params, 'type', defaultType); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchBalance', undefined, params); - const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchBalance', params); - let method = 'privateGetAccount'; - const request = {}; - if (this.isLinear (type, subType)) { - const options = this.safeValue (this.options, type, {}); - const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {}); - method = this.safeString (fetchBalanceOptions, 'method', 'fapiPrivateV2GetAccount'); - type = 'linear'; - } else if (this.isInverse (type, subType)) { - const options = this.safeValue (this.options, type, {}); - const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {}); - method = this.safeString (fetchBalanceOptions, 'method', 'dapiPrivateGetAccount'); - type = 'inverse'; - } else if (marginMode === 'isolated') { - method = 'sapiGetMarginIsolatedAccount'; - const paramSymbols = this.safeValue (params, 'symbols'); - if (paramSymbols !== undefined) { - let symbols = ''; - if (Array.isArray (paramSymbols)) { - symbols = this.marketId (paramSymbols[0]); - for (let i = 1; i < paramSymbols.length; i++) { - const symbol = paramSymbols[i]; - const id = this.marketId (symbol); - symbols += ',' + id; - } - } else { - symbols = paramSymbols; - } - request['symbols'] = symbols; + const response = await this.v4PrivateGetBalances (params); + // [ + // { + // "symbol": "1INCH", + // "balance": 0, + // "balanceInTrade": 0 + // }, + // { + // "symbol": "AAVE", + // "balance": 0, + // "balanceInTrade": 0 + // }, + // { + // "symbol": "ALGO", + // "balance": 0, + // "balanceInTrade": 0 + // } + // ] + return this.parseBalance (response); + } + + // async createOrder (symbol: string, type: OrderType, side: OrderSide, amount, price = undefined, params = {}) { + // /** + // * @method + // * @name youngplatform#createOrder + // * @description create a trade order + // * @param {string} symbol unified symbol of the market to create an order in + // * @param {string} type 'market' or 'limit' + // * @param {string} side 'buy' or 'sell' + // * @param {float} amount how much you want to trade in units of the base currency, quote currency for 'market' 'buy' orders + // * @param {float} [price] the price to fulfill the order, in units of the quote currency, ignored in market orders + // * @param {object} [params] extra parameters specific to the exchange API endpoint + // * @param {float} [params.stopPrice] price to trigger stop orders + // * @param {float} [params.triggerPrice] price to trigger stop orders + // * @param {float} [params.stopLossPrice] price to trigger stop-loss orders + // * @param {float} [params.takeProfitPrice] price to trigger take-profit orders + // * @param {bool} [params.postOnly] true or false + // * @param {string} [params.timeInForce] 'GTC', 'IOC', 'GTD' or 'PO' + // * @param {string} [params.stop_direction] 'UNKNOWN_STOP_DIRECTION', 'STOP_DIRECTION_STOP_UP', 'STOP_DIRECTION_STOP_DOWN' the direction the stopPrice is triggered from + // * @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders + // * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount + // * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} + // */ + // await this.loadMarkets (); + // const market = this.market (symbol); + // const request = { + // 'client_order_id': this.uuid (), + // 'product_id': market['id'], + // 'side': side.toUpperCase (), + // }; + // const stopPrice = this.safeNumberN (params, [ 'stopPrice', 'stop_price', 'triggerPrice' ]); + // const stopLossPrice = this.safeNumber (params, 'stopLossPrice'); + // const takeProfitPrice = this.safeNumber (params, 'takeProfitPrice'); + // const isStop = stopPrice !== undefined; + // const isStopLoss = stopLossPrice !== undefined; + // const isTakeProfit = takeProfitPrice !== undefined; + // const timeInForce = this.safeString (params, 'timeInForce'); + // const postOnly = (timeInForce === 'PO') ? true : this.safeValue2 (params, 'postOnly', 'post_only', false); + // const endTime = this.safeString (params, 'end_time'); + // let stopDirection = this.safeString (params, 'stop_direction'); + // if (type === 'limit') { + // if (isStop) { + // if (stopDirection === undefined) { + // stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_DOWN' : 'STOP_DIRECTION_STOP_UP'; + // } + // if ((timeInForce === 'GTD') || (endTime !== undefined)) { + // if (endTime === undefined) { + // throw new ExchangeError (this.id + ' createOrder() requires an end_time parameter for a GTD order'); + // } + // request['order_configuration'] = { + // 'stop_limit_stop_limit_gtd': { + // 'base_size': this.amountToPrecision (symbol, amount), + // 'limit_price': this.priceToPrecision (symbol, price), + // 'stop_price': this.priceToPrecision (symbol, stopPrice), + // 'stop_direction': stopDirection, + // 'end_time': endTime, + // }, + // }; + // } else { + // request['order_configuration'] = { + // 'stop_limit_stop_limit_gtc': { + // 'base_size': this.amountToPrecision (symbol, amount), + // 'limit_price': this.priceToPrecision (symbol, price), + // 'stop_price': this.priceToPrecision (symbol, stopPrice), + // 'stop_direction': stopDirection, + // }, + // }; + // } + // } else if (isStopLoss || isTakeProfit) { + // let triggerPrice = undefined; + // if (isStopLoss) { + // if (stopDirection === undefined) { + // stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_UP' : 'STOP_DIRECTION_STOP_DOWN'; + // } + // triggerPrice = this.priceToPrecision (symbol, stopLossPrice); + // } else { + // if (stopDirection === undefined) { + // stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_DOWN' : 'STOP_DIRECTION_STOP_UP'; + // } + // triggerPrice = this.priceToPrecision (symbol, takeProfitPrice); + // } + // request['order_configuration'] = { + // 'stop_limit_stop_limit_gtc': { + // 'base_size': this.amountToPrecision (symbol, amount), + // 'limit_price': this.priceToPrecision (symbol, price), + // 'stop_price': triggerPrice, + // 'stop_direction': stopDirection, + // }, + // }; + // } else { + // if ((timeInForce === 'GTD') || (endTime !== undefined)) { + // if (endTime === undefined) { + // throw new ExchangeError (this.id + ' createOrder() requires an end_time parameter for a GTD order'); + // } + // request['order_configuration'] = { + // 'limit_limit_gtd': { + // 'base_size': this.amountToPrecision (symbol, amount), + // 'limit_price': this.priceToPrecision (symbol, price), + // 'end_time': endTime, + // 'post_only': postOnly, + // }, + // }; + // } else { + // request['order_configuration'] = { + // 'limit_limit_gtc': { + // 'base_size': this.amountToPrecision (symbol, amount), + // 'limit_price': this.priceToPrecision (symbol, price), + // 'post_only': postOnly, + // }, + // }; + // } + // } + // } else { + // if (isStop || isStopLoss || isTakeProfit) { + // throw new NotSupported (this.id + ' createOrder() only stop limit orders are supported'); + // } + // if (side === 'buy') { + // let total = undefined; + // let createMarketBuyOrderRequiresPrice = true; + // [ createMarketBuyOrderRequiresPrice, params ] = this.handleOptionAndParams (params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true); + // const cost = this.safeNumber (params, 'cost'); + // params = this.omit (params, 'cost'); + // if (cost !== undefined) { + // total = this.costToPrecision (symbol, cost); + // } else if (createMarketBuyOrderRequiresPrice) { + // if (price === undefined) { + // throw new InvalidOrder (this.id + ' createOrder() requires a price argument for market buy orders on spot markets to calculate the total amount to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend in the amount argument'); + // } else { + // const amountString = this.numberToString (amount); + // const priceString = this.numberToString (price); + // const costRequest = Precise.stringMul (amountString, priceString); + // total = this.costToPrecision (symbol, costRequest); + // } + // } else { + // total = this.costToPrecision (symbol, amount); + // } + // request['order_configuration'] = { + // 'market_market_ioc': { + // 'quote_size': total, + // }, + // }; + // } else { + // request['order_configuration'] = { + // 'market_market_ioc': { + // 'base_size': this.amountToPrecision (symbol, amount), + // }, + // }; + // } + // } + // params = this.omit (params, [ 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time' ]); + // const response = await this.v4PrivatePostOrders (this.extend (request, params)); + // // + // // successful order + // // + // // { + // // "success": true, + // // "failure_reason": "UNKNOWN_FAILURE_REASON", + // // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030", + // // "success_response": { + // // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030", + // // "product_id": "LTC-BTC", + // // "side": "SELL", + // // "client_order_id": "4d760580-6fca-4094-a70b-ebcca8626288" + // // }, + // // "order_configuration": null + // // } + // // + // // failed order + // // + // // { + // // "success": false, + // // "failure_reason": "UNKNOWN_FAILURE_REASON", + // // "order_id": "", + // // "error_response": { + // // "error": "UNSUPPORTED_ORDER_CONFIGURATION", + // // "message": "source is not enabled for trading", + // // "error_details": "", + // // "new_order_failure_reason": "UNSUPPORTED_ORDER_CONFIGURATION" + // // }, + // // "order_configuration": { + // // "limit_limit_gtc": { + // // "base_size": "100", + // // "limit_price": "40000", + // // "post_only": false + // // } + // // } + // // } + // // + // const success = this.safeValue (response, 'success'); + // if (success !== true) { + // const errorResponse = this.safeValue (response, 'error_response'); + // const errorTitle = this.safeString (errorResponse, 'error'); + // const errorMessage = this.safeString (errorResponse, 'message'); + // if (errorResponse !== undefined) { + // this.throwExactlyMatchedException (this.exceptions['exact'], errorTitle, errorMessage); + // this.throwBroadlyMatchedException (this.exceptions['broad'], errorTitle, errorMessage); + // throw new ExchangeError (errorMessage); + // } + // } + // const data = this.safeValue (response, 'success_response', {}); + // return this.parseOrder (data, market); + // } + + sign (path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) { + const version = api[0]; + const signed = api[1] === 'private'; + let fullPath = '/' + version + '/' + api[1] + '/' + this.implodeParams (path, params); + const query = this.omit (params, this.extractParams (path)); + if (method === 'GET') { + if (Object.keys (query).length) { + fullPath += '?' + this.urlencode (query); + } + } + const url = this.urls['api']['rest'] + fullPath; + if (signed) { + const authorization = this.safeString (this.headers, 'Authorization'); + if (authorization !== undefined) { + headers = { + 'Authorization': authorization, + 'Content-Type': 'application/json', + }; + } else if (this.token) { + headers = { + 'Authorization': 'Bearer ' + this.token, + 'Content-Type': 'application/json', + }; + } else { + throw new AuthenticationError (this.id + ' endpoint requires `apiKey` credential'); } - } else if ((type === 'margin') || (marginMode === 'cross')) { - method = 'sapiGetMarginAccount'; - } else if (type === 'savings') { - method = 'sapiGetLendingUnionAccount'; - } else if (type === 'funding') { - method = 'sapiPostAssetGetFundingAsset'; } - const requestParams = this.omit (query, [ 'type', 'symbols' ]); - const response = await this[method] (this.extend (request, requestParams)); - // - // spot - // - // { - // "makerCommission": 10, - // "takerCommission": 10, - // "buyerCommission": 0, - // "sellerCommission": 0, - // "canTrade": true, - // "canWithdraw": true, - // "canDeposit": true, - // "updateTime": 1575357359602, - // "accountType": "MARGIN", - // "balances": [ - // { asset: "BTC", free: "0.00219821", locked: "0.00000000" }, - // ] - // } - // - // margin (cross) - // - // { - // "borrowEnabled":true, - // "marginLevel":"999.00000000", - // "totalAssetOfBtc":"0.00000000", - // "totalLiabilityOfBtc":"0.00000000", - // "totalNetAssetOfBtc":"0.00000000", - // "tradeEnabled":true, - // "transferEnabled":true, - // "userAssets":[ - // {"asset":"MATIC","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}, - // {"asset":"VET","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}, - // {"asset":"USDT","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"} - // ], - // } - // - // margin (isolated) - // - // { - // "info": { - // "assets": [ - // { - // "baseAsset": { - // "asset": "1INCH", - // "borrowEnabled": true, - // "borrowed": "0", - // "free": "0", - // "interest": "0", - // "locked": "0", - // "netAsset": "0", - // "netAssetOfBtc": "0", - // "repayEnabled": true, - // "totalAsset": "0" - // }, - // "quoteAsset": { - // "asset": "USDT", - // "borrowEnabled": true, - // "borrowed": "0", - // "free": "11", - // "interest": "0", - // "locked": "0", - // "netAsset": "11", - // "netAssetOfBtc": "0.00054615", - // "repayEnabled": true, - // "totalAsset": "11" - // }, - // "symbol": "1INCHUSDT", - // "isolatedCreated": true, - // "marginLevel": "999", - // "marginLevelStatus": "EXCESSIVE", - // "marginRatio": "5", - // "indexPrice": "0.59184331", - // "liquidatePrice": "0", - // "liquidateRate": "0", - // "tradeEnabled": true, - // "enabled": true - // }, - // ] - // } - // } - // - // futures (fapi) - // - // fapiPrivateV2GetAccount - // - // { - // "feeTier":0, - // "canTrade":true, - // "canDeposit":true, - // "canWithdraw":true, - // "updateTime":0, - // "totalInitialMargin":"0.00000000", - // "totalMaintMargin":"0.00000000", - // "totalWalletBalance":"0.00000000", - // "totalUnrealizedProfit":"0.00000000", - // "totalMarginBalance":"0.00000000", - // "totalPositionInitialMargin":"0.00000000", - // "totalOpenOrderInitialMargin":"0.00000000", - // "totalCrossWalletBalance":"0.00000000", - // "totalCrossUnPnl":"0.00000000", - // "availableBalance":"0.00000000", - // "maxWithdrawAmount":"0.00000000", - // "assets":[ - // { - // "asset":"BNB", - // "walletBalance":"0.01000000", - // "unrealizedProfit":"0.00000000", - // "marginBalance":"0.01000000", - // "maintMargin":"0.00000000", - // "initialMargin":"0.00000000", - // "positionInitialMargin":"0.00000000", - // "openOrderInitialMargin":"0.00000000", - // "maxWithdrawAmount":"0.01000000", - // "crossWalletBalance":"0.01000000", - // "crossUnPnl":"0.00000000", - // "availableBalance":"0.01000000" - // } - // ], - // "positions":[ - // { - // "symbol":"BTCUSDT", - // "initialMargin":"0", - // "maintMargin":"0", - // "unrealizedProfit":"0.00000000", - // "positionInitialMargin":"0", - // "openOrderInitialMargin":"0", - // "leverage":"21", - // "isolated":false, - // "entryPrice":"0.00000", - // "maxNotional":"5000000", - // "positionSide":"BOTH" - // }, - // ] - // } - // - // fapiPrivateV2GetBalance - // - // [ - // { - // "accountAlias":"FzFzXquXXqoC", - // "asset":"BNB", - // "balance":"0.01000000", - // "crossWalletBalance":"0.01000000", - // "crossUnPnl":"0.00000000", - // "availableBalance":"0.01000000", - // "maxWithdrawAmount":"0.01000000" - // } - // ] - // - // savings - // - // { - // "totalAmountInBTC": "0.3172", - // "totalAmountInUSDT": "10000", - // "totalFixedAmountInBTC": "0.3172", - // "totalFixedAmountInUSDT": "10000", - // "totalFlexibleInBTC": "0", - // "totalFlexibleInUSDT": "0", - // "positionAmountVos": [ - // { - // "asset": "USDT", - // "amount": "10000", - // "amountInBTC": "0.3172", - // "amountInUSDT": "10000" - // }, - // { - // "asset": "BUSD", - // "amount": "0", - // "amountInBTC": "0", - // "amountInUSDT": "0" - // } - // ] - // } - // - // binance pay - // - // [ - // { - // "asset": "BUSD", - // "free": "1129.83", - // "locked": "0", - // "freeze": "0", - // "withdrawing": "0" - // } - // ] - // - return this.parseBalance (response, type, marginMode); - } - - async fetchOrderBook (symbol: string, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchOrderBook - * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data - * @see https://binance-docs.github.io/apidocs/spot/en/#order-book // spot - * @see https://binance-docs.github.io/apidocs/futures/en/#order-book // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#order-book // future - * @see https://binance-docs.github.io/apidocs/voptions/en/#order-book // option - * @param {string} symbol unified symbol of the market to fetch the order book for - * @param {int} [limit] the maximum amount of order book entries to return - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols - */ - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - if (limit !== undefined) { - request['limit'] = limit; // default 100, max 5000, see https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book - } - let response = undefined; - if (market['option']) { - response = await this.eapiPublicGetDepth (this.extend (request, params)); - } else if (market['linear']) { - response = await this.fapiPublicGetDepth (this.extend (request, params)); - } else if (market['inverse']) { - response = await this.dapiPublicGetDepth (this.extend (request, params)); - } else { - response = await this.publicGetDepth (this.extend (request, params)); - } - // - // future - // - // { - // "lastUpdateId":333598053905, - // "E":1618631511986, - // "T":1618631511964, - // "bids":[ - // ["2493.56","20.189"], - // ["2493.54","1.000"], - // ["2493.51","0.005"] - // ], - // "asks":[ - // ["2493.57","0.877"], - // ["2493.62","0.063"], - // ["2493.71","12.054"], - // ] - // } - // - // options (eapi) - // - // { - // "bids": [ - // ["108.7","16.08"], - // ["106","21.29"], - // ["82.4","0.02"] - // ], - // "asks": [ - // ["111.4","19.52"], - // ["119.9","17.6"], - // ["141.2","31"] - // ], - // "T": 1676771382078, - // "u": 1015939 - // } - // - const timestamp = this.safeInteger (response, 'T'); - const orderbook = this.parseOrderBook (response, symbol, timestamp); - orderbook['nonce'] = this.safeInteger2 (response, 'lastUpdateId', 'u'); - return orderbook; - } - - parseTicker (ticker, market: Market = undefined): Ticker { - // - // { - // "symbol": "ETHBTC", - // "priceChange": "0.00068700", - // "priceChangePercent": "2.075", - // "weightedAvgPrice": "0.03342681", - // "prevClosePrice": "0.03310300", - // "lastPrice": "0.03378900", - // "lastQty": "0.07700000", - // "bidPrice": "0.03378900", - // "bidQty": "7.16800000", - // "askPrice": "0.03379000", - // "askQty": "24.00000000", - // "openPrice": "0.03310200", - // "highPrice": "0.03388900", - // "lowPrice": "0.03306900", - // "volume": "205478.41000000", - // "quoteVolume": "6868.48826294", - // "openTime": 1601469986932, - // "closeTime": 1601556386932, - // "firstId": 196098772, - // "lastId": 196186315, - // "count": 87544 - // } - // - // coinm - // - // { - // "baseVolume": "214549.95171161", - // "closeTime": "1621965286847", - // "count": "1283779", - // "firstId": "152560106", - // "highPrice": "39938.3", - // "lastId": "153843955", - // "lastPrice": "37993.4", - // "lastQty": "1", - // "lowPrice": "36457.2", - // "openPrice": "37783.4", - // "openTime": "1621878840000", - // "pair": "BTCUSD", - // "priceChange": "210.0", - // "priceChangePercent": "0.556", - // "symbol": "BTCUSD_PERP", - // "volume": "81990451", - // "weightedAvgPrice": "38215.08713747" - // } - // - // eapi: fetchTicker, fetchTickers - // - // { - // "symbol": "ETH-230510-1825-C", - // "priceChange": "-5.1", - // "priceChangePercent": "-0.1854", - // "lastPrice": "22.4", - // "lastQty": "0", - // "open": "27.5", - // "high": "34.1", - // "low": "22.4", - // "volume": "6.83", - // "amount": "201.44", - // "bidPrice": "21.9", - // "askPrice": "22.4", - // "openTime": 1683614771898, - // "closeTime": 1683695017784, - // "firstTradeId": 12, - // "tradeCount": 22, - // "strikePrice": "1825", - // "exercisePrice": "1845.95341176" - // } - // - // spot bidsAsks - // - // { - // "symbol":"ETHBTC", - // "bidPrice":"0.07466800", - // "bidQty":"5.31990000", - // "askPrice":"0.07466900", - // "askQty":"10.93540000" - // } - // - // usdm bidsAsks - // - // { - // "symbol":"BTCUSDT", - // "bidPrice":"21321.90", - // "bidQty":"33.592", - // "askPrice":"21322.00", - // "askQty":"1.427", - // "time":"1673899207538" - // } - // - // coinm bidsAsks - // - // { - // "symbol":"BTCUSD_PERP", - // "pair":"BTCUSD", - // "bidPrice":"21301.2", - // "bidQty":"188", - // "askPrice":"21301.3", - // "askQty":"10302", - // "time":"1673899278514" - // } - // - const timestamp = this.safeInteger (ticker, 'closeTime'); - let marketType = undefined; - if (('time' in ticker)) { - marketType = 'contract'; - } - if (marketType === undefined) { - marketType = ('bidQty' in ticker) ? 'spot' : 'contract'; - } - const marketId = this.safeString (ticker, 'symbol'); - const symbol = this.safeSymbol (marketId, market, undefined, marketType); - const last = this.safeString (ticker, 'lastPrice'); - const isCoinm = ('baseVolume' in ticker); - let baseVolume = undefined; - let quoteVolume = undefined; - if (isCoinm) { - baseVolume = this.safeString (ticker, 'baseVolume'); - quoteVolume = this.safeString (ticker, 'volume'); - } else { - baseVolume = this.safeString (ticker, 'volume'); - quoteVolume = this.safeString2 (ticker, 'quoteVolume', 'amount'); - } - return this.safeTicker ({ - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'high': this.safeString2 (ticker, 'highPrice', 'high'), - 'low': this.safeString2 (ticker, 'lowPrice', 'low'), - 'bid': this.safeString (ticker, 'bidPrice'), - 'bidVolume': this.safeString (ticker, 'bidQty'), - 'ask': this.safeString (ticker, 'askPrice'), - 'askVolume': this.safeString (ticker, 'askQty'), - 'vwap': this.safeString (ticker, 'weightedAvgPrice'), - 'open': this.safeString2 (ticker, 'openPrice', 'open'), - 'close': last, - 'last': last, - 'previousClose': this.safeString (ticker, 'prevClosePrice'), // previous day close - 'change': this.safeString (ticker, 'priceChange'), - 'percentage': this.safeString (ticker, 'priceChangePercent'), - 'average': undefined, - 'baseVolume': baseVolume, - 'quoteVolume': quoteVolume, - 'info': ticker, - }, market); - } - - async fetchStatus (params = {}) { - /** - * @method - * @name binance#fetchStatus - * @description the latest known information on the availability of the exchange API - * @see https://binance-docs.github.io/apidocs/spot/en/#system-status-system - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure} - */ - const response = await this.sapiGetSystemStatus (params); - // - // { - // "status": 0, // 0: normal,1:system maintenance - // "msg": "normal" // "normal", "system_maintenance" - // } - // - const statusRaw = this.safeString (response, 'status'); - return { - 'status': this.safeString ({ '0': 'ok', '1': 'maintenance' }, statusRaw, statusRaw), - 'updated': undefined, - 'eta': undefined, - 'url': undefined, - 'info': response, - }; - } - - async fetchTicker (symbol: string, params = {}): Promise { - /** - * @method - * @name binance#fetchTicker - * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market - * @see https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics // spot - * @see https://binance-docs.github.io/apidocs/spot/en/#rolling-window-price-change-statistics // spot - * @see https://binance-docs.github.io/apidocs/futures/en/#24hr-ticker-price-change-statistics // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#24hr-ticker-price-change-statistics // future - * @see https://binance-docs.github.io/apidocs/voptions/en/#24hr-ticker-price-change-statistics // option - * @param {string} symbol unified symbol of the market to fetch the ticker for - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {boolean} [params.rolling] (spot only) default false, if true, uses the rolling 24 hour ticker endpoint /api/v3/ticker - * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - let response = undefined; - if (market['option']) { - response = await this.eapiPublicGetTicker (this.extend (request, params)); - } else if (market['linear']) { - response = await this.fapiPublicGetTicker24hr (this.extend (request, params)); - } else if (market['inverse']) { - response = await this.dapiPublicGetTicker24hr (this.extend (request, params)); - } else { - const rolling = this.safeValue (params, 'rolling', false); - params = this.omit (params, 'rolling'); - if (rolling) { - response = await this.publicGetTicker (this.extend (request, params)); - } else { - response = await this.publicGetTicker24hr (this.extend (request, params)); - } - } - if (Array.isArray (response)) { - const firstTicker = this.safeValue (response, 0, {}); - return this.parseTicker (firstTicker, market); - } - return this.parseTicker (response, market); - } - - async fetchBidsAsks (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchBidsAsks - * @description fetches the bid and ask price and volume for multiple markets - * @see https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker // spot - * @see https://binance-docs.github.io/apidocs/futures/en/#symbol-order-book-ticker // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#symbol-order-book-ticker // future - * @param {string[]|undefined} symbols unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} - */ - await this.loadMarkets (); - symbols = this.marketSymbols (symbols); - let market = undefined; - if (symbols !== undefined) { - const first = this.safeString (symbols, 0); - market = this.market (first); - } - let type = undefined; - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchBidsAsks', market, params); - [ type, params ] = this.handleMarketTypeAndParams ('fetchBidsAsks', market, params); - let response = undefined; - if (this.isLinear (type, subType)) { - response = await this.fapiPublicGetTickerBookTicker (params); - } else if (this.isInverse (type, subType)) { - response = await this.dapiPublicGetTickerBookTicker (params); - } else { - response = await this.publicGetTickerBookTicker (params); - } - return this.parseTickers (response, symbols); - } - - async fetchTickers (symbols: Strings = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchTickers - * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market - * @see https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics // spot - * @see https://binance-docs.github.io/apidocs/futures/en/#24hr-ticker-price-change-statistics // swap - * @see https://binance-docs.github.io/apidocs/delivery/en/#24hr-ticker-price-change-statistics // future - * @see https://binance-docs.github.io/apidocs/voptions/en/#24hr-ticker-price-change-statistics // option - * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} - */ - await this.loadMarkets (); - let type = undefined; - let market = undefined; - symbols = this.marketSymbols (symbols, undefined, true, true, true); - if (symbols !== undefined) { - const first = this.safeString (symbols, 0); - market = this.market (first); - } - [ type, params ] = this.handleMarketTypeAndParams ('fetchTickers', market, params); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchTickers', market, params); - const query = this.omit (params, 'type'); - let defaultMethod = undefined; - if (type === 'option') { - defaultMethod = 'eapiPublicGetTicker'; - } else if (this.isLinear (type, subType)) { - defaultMethod = 'fapiPublicGetTicker24hr'; - } else if (this.isInverse (type, subType)) { - defaultMethod = 'dapiPublicGetTicker24hr'; - } else { - defaultMethod = 'publicGetTicker24hr'; - } - const method = this.safeString (this.options, 'fetchTickersMethod', defaultMethod); - const response = await this[method] (query); - return this.parseTickers (response, symbols); - } - - parseOHLCV (ohlcv, market: Market = undefined): OHLCV { - // when api method = publicGetKlines || fapiPublicGetKlines || dapiPublicGetKlines - // [ - // 1591478520000, // open time - // "0.02501300", // open - // "0.02501800", // high - // "0.02500000", // low - // "0.02500000", // close - // "22.19000000", // volume - // 1591478579999, // close time - // "0.55490906", // quote asset volume, base asset volume for dapi - // 40, // number of trades - // "10.92900000", // taker buy base asset volume - // "0.27336462", // taker buy quote asset volume - // "0" // ignore - // ] - // - // when api method = fapiPublicGetMarkPriceKlines || fapiPublicGetIndexPriceKlines - // [ - // [ - // 1591256460000, // Open time - // "9653.29201333", // Open - // "9654.56401333", // High - // "9653.07367333", // Low - // "9653.07367333", // Close (or latest price) - // "0", // Ignore - // 1591256519999, // Close time - // "0", // Ignore - // 60, // Number of bisic data - // "0", // Ignore - // "0", // Ignore - // "0" // Ignore - // ] - // ] - // - // options - // - // { - // "open": "32.2", - // "high": "32.2", - // "low": "32.2", - // "close": "32.2", - // "volume": "0", - // "interval": "5m", - // "tradeCount": 0, - // "takerVolume": "0", - // "takerAmount": "0", - // "amount": "0", - // "openTime": 1677096900000, - // "closeTime": 1677097200000 - // } - // - const volumeIndex = (market['inverse']) ? 7 : 5; - return [ - this.safeInteger2 (ohlcv, 0, 'closeTime'), - this.safeNumber2 (ohlcv, 1, 'open'), - this.safeNumber2 (ohlcv, 2, 'high'), - this.safeNumber2 (ohlcv, 3, 'low'), - this.safeNumber2 (ohlcv, 4, 'close'), - this.safeNumber2 (ohlcv, volumeIndex, 'volume'), - ]; - } - - async fetchOHLCV (symbol: string, timeframe = '1m', since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchOHLCV - * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market - * @see https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/voptions/en/#kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/futures/en/#index-price-kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/futures/en/#mark-price-kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/delivery/en/#index-price-kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/delivery/en/#mark-price-kline-candlestick-data - * @see https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data - * @param {string} symbol unified symbol of the market to fetch OHLCV data for - * @param {string} timeframe the length of time each candle represents - * @param {int} [since] timestamp in ms of the earliest candle to fetch - * @param {int} [limit] the maximum amount of candles to fetch - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.price] "mark" or "index" for mark price and index price candles - * @param {int} [params.until] timestamp in ms of the latest candle to fetch - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchOHLCV', 'paginate', false); - if (paginate) { - return await this.fetchPaginatedCallDeterministic ('fetchOHLCV', symbol, since, limit, timeframe, params, 1000) as OHLCV[]; - } - const market = this.market (symbol); - // binance docs say that the default limit 500, max 1500 for futures, max 1000 for spot markets - // the reality is that the time range wider than 500 candles won't work right - const defaultLimit = 500; - const maxLimit = 1500; - const price = this.safeString (params, 'price'); - const until = this.safeInteger (params, 'until'); - params = this.omit (params, [ 'price', 'until' ]); - limit = (limit === undefined) ? defaultLimit : Math.min (limit, maxLimit); - const request = { - 'interval': this.safeString (this.timeframes, timeframe, timeframe), - 'limit': limit, - }; - if (price === 'index') { - request['pair'] = market['id']; // Index price takes this argument instead of symbol - } else { - request['symbol'] = market['id']; - } - // const duration = this.parseTimeframe (timeframe); - if (since !== undefined) { - request['startTime'] = since; - // - // It didn't work before without the endTime - // https://github.com/ccxt/ccxt/issues/8454 - // - if (market['inverse']) { - if (since > 0) { - const duration = this.parseTimeframe (timeframe); - const endTime = this.sum (since, limit * duration * 1000 - 1); - const now = this.milliseconds (); - request['endTime'] = Math.min (now, endTime); - } - } - } - if (until !== undefined) { - request['endTime'] = until; - } - let method = 'publicGetKlines'; - if (market['option']) { - method = 'eapiPublicGetKlines'; - } else if (price === 'mark') { - if (market['inverse']) { - method = 'dapiPublicGetMarkPriceKlines'; - } else { - method = 'fapiPublicGetMarkPriceKlines'; - } - } else if (price === 'index') { - if (market['inverse']) { - method = 'dapiPublicGetIndexPriceKlines'; - } else { - method = 'fapiPublicGetIndexPriceKlines'; - } - } else if (market['linear']) { - method = 'fapiPublicGetKlines'; - } else if (market['inverse']) { - method = 'dapiPublicGetKlines'; - } - const response = await this[method] (this.extend (request, params)); - // - // [ - // [1591478520000,"0.02501300","0.02501800","0.02500000","0.02500000","22.19000000",1591478579999,"0.55490906",40,"10.92900000","0.27336462","0"], - // [1591478580000,"0.02499600","0.02500900","0.02499400","0.02500300","21.34700000",1591478639999,"0.53370468",24,"7.53800000","0.18850725","0"], - // [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"], - // ] - // - // options (eapi) - // - // [ - // { - // "open": "32.2", - // "high": "32.2", - // "low": "32.2", - // "close": "32.2", - // "volume": "0", - // "interval": "5m", - // "tradeCount": 0, - // "takerVolume": "0", - // "takerAmount": "0", - // "amount": "0", - // "openTime": 1677096900000, - // "closeTime": 1677097200000 - // } - // ] - // - return this.parseOHLCVs (response, market, timeframe, since, limit); + return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } parseTrade (trade, market: Market = undefined): Trade { - if ('isDustTrade' in trade) { - return this.parseDustTrade (trade, market); - } - // - // aggregate trades - // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list - // - // { - // "a": 26129, // Aggregate tradeId - // "p": "0.01633102", // Price - // "q": "4.70443515", // Quantity - // "f": 27781, // First tradeId - // "l": 27781, // Last tradeId - // "T": 1498793709153, // Timestamp - // "m": true, // Was the buyer the maker? - // "M": true // Was the trade the best price match? - // } - // - // REST: aggregate trades for swap & future (both linear and inverse) - // - // { - // "a": "269772814", - // "p": "25864.1", - // "q": "3", - // "f": "662149354", - // "l": "662149355", - // "T": "1694209776022", - // "m": false, - // } - // - // recent public trades and old public trades - // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#recent-trades-list - // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#old-trade-lookup-market_data - // - // { - // "id": 28457, - // "price": "4.00000100", - // "qty": "12.00000000", - // "time": 1499865549590, - // "isBuyerMaker": true, - // "isBestMatch": true - // } - // - // private trades - // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-trade-list-user_data - // - // { - // "symbol": "BNBBTC", - // "id": 28457, - // "orderId": 100234, - // "price": "4.00000100", - // "qty": "12.00000000", - // "commission": "10.10000000", - // "commissionAsset": "BNB", - // "time": 1499865549590, - // "isBuyer": true, - // "isMaker": false, - // "isBestMatch": true - // } - // - // futures trades - // https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data - // - // { - // "accountId": 20, - // "buyer": False, - // "commission": "-0.07819010", - // "commissionAsset": "USDT", - // "counterPartyId": 653, - // "id": 698759, - // "maker": False, - // "orderId": 25851813, - // "price": "7819.01", - // "qty": "0.002", - // "quoteQty": "0.01563", - // "realizedPnl": "-0.91539999", - // "side": "SELL", - // "symbol": "BTCUSDT", - // "time": 1569514978020 - // } - // { - // "symbol": "BTCUSDT", - // "id": 477128891, - // "orderId": 13809777875, - // "side": "SELL", - // "price": "38479.55", - // "qty": "0.001", - // "realizedPnl": "-0.00009534", - // "marginAsset": "USDT", - // "quoteQty": "38.47955", - // "commission": "-0.00076959", - // "commissionAsset": "USDT", - // "time": 1612733566708, - // "positionSide": "BOTH", - // "maker": true, - // "buyer": false - // } - // - // { respType: FULL } - // - // { - // "price": "4000.00000000", - // "qty": "1.00000000", - // "commission": "4.00000000", - // "commissionAsset": "USDT", - // "tradeId": "1234", - // } - // - // options: fetchMyTrades - // - // { - // "id": 1125899906844226012, - // "tradeId": 73, - // "orderId": 4638761100843040768, - // "symbol": "ETH-230211-1500-C", - // "price": "18.70000000", - // "quantity": "-0.57000000", - // "fee": "0.17305890", - // "realizedProfit": "-3.53400000", - // "side": "SELL", - // "type": "LIMIT", - // "volatility": "0.30000000", - // "liquidity": "MAKER", - // "time": 1676085216845, - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT" - // } - // - // options: fetchTrades - // - // { - // "id": 1, - // "symbol": "ETH-230216-1500-C", - // "price": "35.5", - // "qty": "0.03", - // "quoteQty": "1.065", - // "side": 1, - // "time": 1676366446072 - // } - // - const timestamp = this.safeInteger2 (trade, 'T', 'time'); - const price = this.safeString2 (trade, 'p', 'price'); - let amount = this.safeString2 (trade, 'q', 'qty'); - amount = this.safeString (trade, 'quantity', amount); - const cost = this.safeString2 (trade, 'quoteQty', 'baseQty'); // inverse futures - const marketId = this.safeString (trade, 'symbol'); - const isSpotTrade = ('isIsolated' in trade) || ('M' in trade) || ('orderListId' in trade); - const marketType = isSpotTrade ? 'spot' : 'contract'; - market = this.safeMarket (marketId, market, undefined, marketType); - const symbol = market['symbol']; - let id = this.safeString2 (trade, 't', 'a'); - id = this.safeString2 (trade, 'tradeId', 'id', id); - let side = undefined; - const orderId = this.safeString (trade, 'orderId'); - const buyerMaker = this.safeValue2 (trade, 'm', 'isBuyerMaker'); - let takerOrMaker = undefined; - if (buyerMaker !== undefined) { - side = buyerMaker ? 'sell' : 'buy'; // this is reversed intentionally - } else if ('side' in trade) { - side = this.safeStringLower (trade, 'side'); - } else { - if ('isBuyer' in trade) { - side = trade['isBuyer'] ? 'buy' : 'sell'; // this is a true side - } - } - let fee = undefined; - if ('commission' in trade) { - fee = { - 'cost': this.safeString (trade, 'commission'), - 'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAsset')), - }; - } - if ('isMaker' in trade) { - takerOrMaker = trade['isMaker'] ? 'maker' : 'taker'; - } - if ('maker' in trade) { - takerOrMaker = trade['maker'] ? 'maker' : 'taker'; - } - if (('optionSide' in trade) || market['option']) { - const settle = this.safeCurrencyCode (this.safeString (trade, 'quoteAsset', 'USDT')); - takerOrMaker = this.safeStringLower (trade, 'liquidity'); - if ('fee' in trade) { - fee = { - 'cost': this.safeString (trade, 'fee'), - 'currency': settle, - }; - } - if ((side !== 'buy') && (side !== 'sell')) { - side = (side === '1') ? 'buy' : 'sell'; - } - if ('optionSide' in trade) { - if (side !== 'buy') { - amount = Precise.stringMul ('-1', amount); - } - } - } + // { + // "id": 123456, + // "orderId": 789012, + // "baseCurrency": "USD", + // "quoteCurrency": "BTC", + // "side": "Buy", + // "taker": true, + // "amount": 10.25, + // "volume": 0.002, + // "rate": 50000.75, + // "brokerage": 0.0025, + // "brokerageCurrency": "USD", + // "executionDate": "2024-02-05T14:30:00" + // } + const datetime = this.safeString (trade, 'executionDate'); + const side = this.safeStringLower (trade, 'side'); + const taker = this.safeValue (trade, 'taker'); + const base = this.safeString (trade, 'market'); + const quote = this.safeString (trade, 'quote'); + const symbol = base + '/' + quote; + const price = this.safeNumber (trade, 'rate'); + const amount = this.safeNumber (trade, 'amount'); + const priceString = this.numberToString (price); + const amountString = this.numberToString (amount); + const cost = Precise.stringMul (priceString, amountString); return this.safeTrade ({ 'info': trade, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), + 'id': this.safeString (trade, 'id'), + 'order': this.safeString (trade, 'orderId'), + 'timestamp': this.parse8601 (datetime), + 'datetime': datetime, 'symbol': symbol, - 'id': id, - 'order': orderId, - 'type': this.safeStringLower (trade, 'type'), + 'type': undefined, 'side': side, - 'takerOrMaker': takerOrMaker, - 'price': price, - 'amount': amount, + 'takerOrMaker': taker ? 'taker' : 'maker', + 'price': priceString, + 'amount': amountString, 'cost': cost, - 'fee': fee, - }, market); + 'fee': { + 'cost': undefined, + 'currency': quote, + }, + }); } - async fetchTrades (symbol: string, since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchTrades - * @description get the list of most recent trades for a particular symbol - * Default fetchTradesMethod - * @see https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list // publicGetAggTrades (spot) - * @see https://binance-docs.github.io/apidocs/futures/en/#compressed-aggregate-trades-list // fapiPublicGetAggTrades (swap) - * @see https://binance-docs.github.io/apidocs/delivery/en/#compressed-aggregate-trades-list // dapiPublicGetAggTrades (future) - * @see https://binance-docs.github.io/apidocs/voptions/en/#recent-trades-list // eapiPublicGetTrades (option) - * Other fetchTradesMethod - * @see https://binance-docs.github.io/apidocs/spot/en/#recent-trades-list // publicGetTrades (spot) - * @see https://binance-docs.github.io/apidocs/futures/en/#recent-trades-list // fapiPublicGetTrades (swap) - * @see https://binance-docs.github.io/apidocs/delivery/en/#recent-trades-list // dapiPublicGetTrades (future) - * @see https://binance-docs.github.io/apidocs/spot/en/#old-trade-lookup-market_data // publicGetHistoricalTrades (spot) - * @see https://binance-docs.github.io/apidocs/future/en/#old-trade-lookup-market_data // fapiPublicGetHistoricalTrades (swap) - * @see https://binance-docs.github.io/apidocs/delivery/en/#old-trade-lookup-market_data // dapiPublicGetHistoricalTrades (future) - * @see https://binance-docs.github.io/apidocs/voptions/en/#old-trade-lookup-market_data // eapiPublicGetHistoricalTrades (option) - * @param {string} symbol unified symbol of the market to fetch trades for - * @param {int} [since] only used when fetchTradesMethod is 'publicGetAggTrades', 'fapiPublicGetAggTrades', or 'dapiPublicGetAggTrades' - * @param {int} [limit] default 500, max 1000 - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {int} [params.until] only used when fetchTradesMethod is 'publicGetAggTrades', 'fapiPublicGetAggTrades', or 'dapiPublicGetAggTrades' - * @param {int} [params.fetchTradesMethod] 'publicGetAggTrades' (spot default), 'fapiPublicGetAggTrades' (swap default), 'dapiPublicGetAggTrades' (future default), 'eapiPublicGetTrades' (option default), 'publicGetTrades', 'fapiPublicGetTrades', 'dapiPublicGetTrades', 'publicGetHistoricalTrades', 'fapiPublicGetHistoricalTrades', 'dapiPublicGetHistoricalTrades', 'eapiPublicGetHistoricalTrades' - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * - * EXCHANGE SPECIFIC PARAMETERS - * @param {int} [params.fromId] trade id to fetch from, default gets most recent trades, not used when fetchTradesMethod is 'publicGetTrades', 'fapiPublicGetTrades', 'dapiPublicGetTrades', or 'eapiPublicGetTrades' - * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchTrades', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchTrades', symbol, since, limit, params) as Trade[]; - } - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - // 'fromId': 123, // ID to get aggregate trades from INCLUSIVE. - // 'startTime': 456, // Timestamp in ms to get aggregate trades from INCLUSIVE. - // 'endTime': 789, // Timestamp in ms to get aggregate trades until INCLUSIVE. - // 'limit': 500, // default = 500, maximum = 1000 - }; - let method = this.safeString (this.options, 'fetchTradesMethod'); - method = this.safeString2 (params, 'fetchTradesMethod', 'method', method); - if (method === undefined) { - if (market['option']) { - method = 'eapiPublicGetTrades'; - } else if (market['linear']) { - method = 'fapiPublicGetAggTrades'; - } else if (market['inverse']) { - method = 'dapiPublicGetAggTrades'; + parseBalance (response, params = {}) { + // [ + // { + // "symbol": "1INCH", + // "balance": 0, + // "balanceInTrade": 0 + // }, + // { + // "symbol": "AAVE", + // "balance": 0, + // "balanceInTrade": 0 + // }, + // { + // "symbol": "ALGO", + // "balance": 0, + // "balanceInTrade": 0 + // } + // ] + const result = { 'info': response }; + for (let b = 0; b < response.length; b++) { + const balance = response[b]; + const currencyId = this.safeString (balance, 'symbol'); + const code = this.safeCurrencyCode (currencyId); + const free = this.safeNumber (balance, 'balance'); + const used = this.safeNumber (balance, 'balanceInTrade'); + const freeString = this.numberToString (free); + const usedString = this.numberToString (used); + const total = Precise.stringAdd (freeString, usedString); + let account = this.safeValue (result, code); + if (account === undefined) { + account = this.account (); + account['free'] = free; + account['used'] = used; + account['total'] = total; } else { - method = 'publicGetAggTrades'; - } - } - if (!market['option']) { - if (since !== undefined) { - request['startTime'] = since; - // https://github.com/ccxt/ccxt/issues/6400 - // https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list - request['endTime'] = this.sum (since, 3600000); - } - const until = this.safeInteger (params, 'until'); - if (until !== undefined) { - request['endTime'] = until; + account['free'] = Precise.stringAdd (account['free'], freeString); + account['used'] = Precise.stringAdd (account['used'], usedString); + account['total'] = Precise.stringAdd (account['total'], total); } + result[code] = account; } - if (limit !== undefined) { - const isFutureOrSwap = (market['swap'] || market['future']); - request['limit'] = isFutureOrSwap ? Math.min (limit, 1000) : limit; // default = 500, maximum = 1000 - } - params = this.omit (params, [ 'until', 'fetchTradesMethod' ]); - // - // Caveats: - // - default limit (500) applies only if no other parameters set, trades up - // to the maximum limit may be returned to satisfy other parameters - // - if both limit and time window is set and time window contains more - // trades than the limit then the last trades from the window are returned - // - "tradeId" accepted and returned by this method is "aggregate" trade id - // which is different from actual trade id - // - setting both fromId and time window results in error - const response = await this[method] (this.extend (request, params)); - // - // aggregate trades - // - // [ - // { - // "a": 26129, // Aggregate tradeId - // "p": "0.01633102", // Price - // "q": "4.70443515", // Quantity - // "f": 27781, // First tradeId - // "l": 27781, // Last tradeId - // "T": 1498793709153, // Timestamp - // "m": true, // Was the buyer the maker? - // "M": true // Was the trade the best price match? - // } - // ] - // - // inverse (swap & future) - // - // [ - // { - // "a": "269772814", - // "p": "25864.1", - // "q": "3", - // "f": "662149354", - // "l": "662149355", - // "T": "1694209776022", - // "m": false, - // }, - // ] - // - // recent public trades and historical public trades - // - // [ - // { - // "id": 28457, - // "price": "4.00000100", - // "qty": "12.00000000", - // "time": 1499865549590, - // "isBuyerMaker": true, - // "isBestMatch": true - // } - // ] - // - // options (eapi) - // - // [ - // { - // "id": 1, - // "symbol": "ETH-230216-1500-C", - // "price": "35.5", - // "qty": "0.03", - // "quoteQty": "1.065", - // "side": 1, - // "time": 1676366446072 - // }, - // ] - // - return this.parseTrades (response, market, since, limit); - } - - async editSpotOrder (id: string, symbol, type, side, amount, price = undefined, params = {}) { - /** - * @method - * @name binance#editSpotOrder - * @ignore - * @description edit a trade order - * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade - * @param {string} id cancel order id - * @param {string} symbol unified symbol of the market to create an order in - * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' - * @param {string} side 'buy' or 'sell' - * @param {float} amount how much of currency you want to trade in units of base currency - * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - if (!market['spot']) { - throw new NotSupported (this.id + ' editSpotOrder() does not support ' + market['type'] + ' orders'); - } - const payload = this.editSpotOrderRequest (id, symbol, type, side, amount, price, params); - const response = await this.privatePostOrderCancelReplace (payload); - // - // spot - // - // { - // "cancelResult": "SUCCESS", - // "newOrderResult": "SUCCESS", - // "cancelResponse": { - // "symbol": "BTCUSDT", - // "origClientOrderId": "web_3f6286480b194b079870ac75fb6978b7", - // "orderId": 16383156620, - // "orderListId": -1, - // "clientOrderId": "Azt6foVTTgHPNhqBf41TTt", - // "price": "14000.00000000", - // "origQty": "0.00110000", - // "executedQty": "0.00000000", - // "cummulativeQuoteQty": "0.00000000", - // "status": "CANCELED", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY" - // }, - // "newOrderResponse": { - // "symbol": "BTCUSDT", - // "orderId": 16383176297, - // "orderListId": -1, - // "clientOrderId": "x-R4BD3S8222ecb58eb9074fb1be018c", - // "transactTime": 1670891847932, - // "price": "13500.00000000", - // "origQty": "0.00085000", - // "executedQty": "0.00000000", - // "cummulativeQuoteQty": "0.00000000", - // "status": "NEW", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY", - // "fills": [] - // } - // } - // - const data = this.safeValue (response, 'newOrderResponse'); - return this.parseOrder (data, market); - } - - editSpotOrderRequest (id: string, symbol, type, side, amount, price = undefined, params = {}) { - /** - * @method - * @ignore - * @name binance#editSpotOrderRequest - * @description helper function to build request for editSpotOrder - * @param {string} id order id to be edited - * @param {string} symbol unified symbol of the market to create an order in - * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' - * @param {string} side 'buy' or 'sell' - * @param {float} amount how much of currency you want to trade in units of base currency - * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders - * @param {object} params extra parameters specific to the exchange API endpoint - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @returns {object} request to be sent to the exchange - */ - const market = this.market (symbol); - const clientOrderId = this.safeStringN (params, [ 'newClientOrderId', 'clientOrderId', 'origClientOrderId' ]); - const request = { - 'symbol': market['id'], - 'side': side.toUpperCase (), - }; - const initialUppercaseType = type.toUpperCase (); - let uppercaseType = initialUppercaseType; - const postOnly = this.isPostOnly (initialUppercaseType === 'MARKET', initialUppercaseType === 'LIMIT_MAKER', params); - if (postOnly) { - uppercaseType = 'LIMIT_MAKER'; - } - request['type'] = uppercaseType; - const stopPrice = this.safeNumber2 (params, 'stopPrice', 'triggerPrice'); - if (stopPrice !== undefined) { - if (uppercaseType === 'MARKET') { - uppercaseType = 'STOP_LOSS'; - } else if (uppercaseType === 'LIMIT') { - uppercaseType = 'STOP_LOSS_LIMIT'; - } - } - const validOrderTypes = this.safeValue (market['info'], 'orderTypes'); - if (!this.inArray (uppercaseType, validOrderTypes)) { - if (initialUppercaseType !== uppercaseType) { - throw new InvalidOrder (this.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders'); - } else { - throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market'); - } - } - if (clientOrderId === undefined) { - const broker = this.safeValue (this.options, 'broker'); - if (broker !== undefined) { - const brokerId = this.safeString (broker, 'spot'); - if (brokerId !== undefined) { - request['newClientOrderId'] = brokerId + this.uuid22 (); - } - } - } else { - request['newClientOrderId'] = clientOrderId; - } - request['newOrderRespType'] = this.safeValue (this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills - let timeInForceIsRequired = false; - let priceIsRequired = false; - let stopPriceIsRequired = false; - let quantityIsRequired = false; - if (uppercaseType === 'MARKET') { - const quoteOrderQty = this.safeValue (this.options, 'quoteOrderQty', true); - if (quoteOrderQty) { - const quoteOrderQtyNew = this.safeValue2 (params, 'quoteOrderQty', 'cost'); - const precision = market['precision']['price']; - if (quoteOrderQtyNew !== undefined) { - request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQtyNew, TRUNCATE, precision, this.precisionMode); - } else if (price !== undefined) { - const amountString = this.numberToString (amount); - const priceString = this.numberToString (price); - const quoteOrderQuantity = Precise.stringMul (amountString, priceString); - request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQuantity, TRUNCATE, precision, this.precisionMode); - } else { - quantityIsRequired = true; - } - } else { - quantityIsRequired = true; - } - } else if (uppercaseType === 'LIMIT') { - priceIsRequired = true; - timeInForceIsRequired = true; - quantityIsRequired = true; - } else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) { - stopPriceIsRequired = true; - quantityIsRequired = true; - } else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) { - quantityIsRequired = true; - stopPriceIsRequired = true; - priceIsRequired = true; - timeInForceIsRequired = true; - } else if (uppercaseType === 'LIMIT_MAKER') { - priceIsRequired = true; - quantityIsRequired = true; - } - if (quantityIsRequired) { - request['quantity'] = this.amountToPrecision (symbol, amount); - } - if (priceIsRequired) { - if (price === undefined) { - throw new InvalidOrder (this.id + ' editOrder() requires a price argument for a ' + type + ' order'); - } - request['price'] = this.priceToPrecision (symbol, price); - } - if (timeInForceIsRequired) { - request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - } - if (stopPriceIsRequired) { - if (stopPrice === undefined) { - throw new InvalidOrder (this.id + ' editOrder() requires a stopPrice extra param for a ' + type + ' order'); - } else { - request['stopPrice'] = this.priceToPrecision (symbol, stopPrice); - } - } - request['cancelReplaceMode'] = 'STOP_ON_FAILURE'; // If the cancel request fails, the new order placement will not be attempted. - const cancelId = this.safeString2 (params, 'cancelNewClientOrderId', 'cancelOrigClientOrderId'); - if (cancelId === undefined) { - request['cancelOrderId'] = id; // user can provide either cancelOrderId, cancelOrigClientOrderId or cancelOrigClientOrderId - } - // remove timeInForce from params because PO is only used by this.isPostOnly and it's not a valid value for Binance - if (this.safeString (params, 'timeInForce') === 'PO') { - params = this.omit (params, [ 'timeInForce' ]); - } - params = this.omit (params, [ 'quoteOrderQty', 'cost', 'stopPrice', 'newClientOrderId', 'clientOrderId', 'postOnly' ]); - return this.extend (request, params); - } - - async editContractOrder (id: string, symbol, type, side, amount, price = undefined, params = {}) { - /** - * @method - * @name binance#editContractOrder - * @description edit a trade order - * @see https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-order-trade - * @param {string} id cancel order id - * @param {string} symbol unified symbol of the market to create an order in - * @param {string} type 'market' or 'limit' - * @param {string} side 'buy' or 'sell' - * @param {float} amount how much of currency you want to trade in units of base currency - * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - if (!market['contract']) { - throw new NotSupported (this.id + ' editContractOrder() does not support ' + market['type'] + ' orders'); - } - const request = { - 'symbol': market['id'], - 'side': side.toUpperCase (), - }; - const clientOrderId = this.safeStringN (params, [ 'newClientOrderId', 'clientOrderId', 'origClientOrderId' ]); - request['orderId'] = id; - request['quantity'] = this.amountToPrecision (symbol, amount); - if (price !== undefined) { - request['price'] = this.priceToPrecision (symbol, price); - } - if (clientOrderId !== undefined) { - request['origClientOrderId'] = clientOrderId; - } - params = this.omit (params, [ 'clientOrderId', 'newClientOrderId' ]); - let response = undefined; - if (market['linear']) { - response = await this.fapiPrivatePutOrder (this.extend (request, params)); - } else if (market['inverse']) { - response = await this.dapiPrivatePutOrder (this.extend (request, params)); - } - // - // swap and future - // - // { - // "orderId": 151007482392, - // "symbol": "BTCUSDT", - // "status": "NEW", - // "clientOrderId": "web_pCCGp9AIHjziKLlpGpXI", - // "price": "25000", - // "avgPrice": "0.00000", - // "origQty": "0.001", - // "executedQty": "0", - // "cumQty": "0", - // "cumQuote": "0", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "BUY", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, - // "origType": "LIMIT", - // "updateTime": 1684300587845 - // } - // - return this.parseOrder (response, market); - } - - async editOrder (id: string, symbol, type, side, amount = undefined, price = undefined, params = {}) { - /** - * @method - * @name binance#editOrder - * @description edit a trade order - * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-order-trade - * @param {string} id cancel order id - * @param {string} symbol unified symbol of the market to create an order in - * @param {string} type 'market' or 'limit' - * @param {string} side 'buy' or 'sell' - * @param {float} amount how much of currency you want to trade in units of base currency - * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - if (market['option']) { - throw new NotSupported (this.id + ' editOrder() does not support ' + market['type'] + ' orders'); - } - if (market['spot']) { - return await this.editSpotOrder (id, symbol, type, side, amount, price, params); - } else { - return await this.editContractOrder (id, symbol, type, side, amount, price, params); - } - } - - parseOrderStatus (status) { - const statuses = { - 'NEW': 'open', - 'PARTIALLY_FILLED': 'open', - 'ACCEPTED': 'open', - 'FILLED': 'closed', - 'CANCELED': 'canceled', - 'CANCELLED': 'canceled', - 'PENDING_CANCEL': 'canceling', // currently unused - 'REJECTED': 'rejected', - 'EXPIRED': 'expired', - 'EXPIRED_IN_MATCH': 'expired', - }; - return this.safeString (statuses, status, status); - } - - parseOrder (order, market: Market = undefined): Order { - // - // spot - // - // { - // "symbol": "LTCBTC", - // "orderId": 1, - // "clientOrderId": "myOrder1", - // "price": "0.1", - // "origQty": "1.0", - // "executedQty": "0.0", - // "cummulativeQuoteQty": "0.0", - // "status": "NEW", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY", - // "stopPrice": "0.0", - // "icebergQty": "0.0", - // "time": 1499827319559, - // "updateTime": 1499827319559, - // "isWorking": true - // } - // - // spot: editOrder - // - // { - // "symbol": "BTCUSDT", - // "orderId": 16383176297, - // "orderListId": -1, - // "clientOrderId": "x-R4BD3S8222ecb58eb9074fb1be018c", - // "transactTime": 1670891847932, - // "price": "13500.00000000", - // "origQty": "0.00085000", - // "executedQty": "0.00000000", - // "cummulativeQuoteQty": "0.00000000", - // "status": "NEW", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY", - // "fills": [] - // } - // - // swap and future: editOrder - // - // { - // "orderId": 151007482392, - // "symbol": "BTCUSDT", - // "status": "NEW", - // "clientOrderId": "web_pCCGp9AIHjziKLlpGpXI", - // "price": "25000", - // "avgPrice": "0.00000", - // "origQty": "0.001", - // "executedQty": "0", - // "cumQty": "0", - // "cumQuote": "0", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "BUY", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, - // "origType": "LIMIT", - // "updateTime": 1684300587845 - // } - // - // futures - // - // { - // "symbol": "BTCUSDT", - // "orderId": 1, - // "clientOrderId": "myOrder1", - // "price": "0.1", - // "origQty": "1.0", - // "executedQty": "1.0", - // "cumQuote": "10.0", - // "status": "NEW", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY", - // "stopPrice": "0.0", - // "updateTime": 1499827319559 - // } - // - // createOrder with { "newOrderRespType": "FULL" } - // - // { - // "symbol": "BTCUSDT", - // "orderId": 5403233939, - // "orderListId": -1, - // "clientOrderId": "x-R4BD3S825e669e75b6c14f69a2c43e", - // "transactTime": 1617151923742, - // "price": "0.00000000", - // "origQty": "0.00050000", - // "executedQty": "0.00050000", - // "cummulativeQuoteQty": "29.47081500", - // "status": "FILLED", - // "timeInForce": "GTC", - // "type": "MARKET", - // "side": "BUY", - // "fills": [ - // { - // "price": "58941.63000000", - // "qty": "0.00050000", - // "commission": "0.00007050", - // "commissionAsset": "BNB", - // "tradeId": 737466631 - // } - // ] - // } - // - // delivery - // - // { - // "orderId": "18742727411", - // "symbol": "ETHUSD_PERP", - // "pair": "ETHUSD", - // "status": "FILLED", - // "clientOrderId": "x-xcKtGhcu3e2d1503fdd543b3b02419", - // "price": "0", - // "avgPrice": "4522.14", - // "origQty": "1", - // "executedQty": "1", - // "cumBase": "0.00221134", - // "timeInForce": "GTC", - // "type": "MARKET", - // "reduceOnly": false, - // "closePosition": false, - // "side": "SELL", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, - // "origType": "MARKET", - // "time": "1636061952660", - // "updateTime": "1636061952660" - // } - // - // option: createOrder, fetchOrder, fetchOpenOrders, fetchOrders - // - // { - // "orderId": 4728833085436977152, - // "symbol": "ETH-230211-1500-C", - // "price": "10.0", - // "quantity": "1.00", - // "executedQty": "0.00", - // "fee": "0", - // "side": "BUY", - // "type": "LIMIT", - // "timeInForce": "GTC", - // "reduceOnly": false, - // "postOnly": false, - // "createTime": 1676083034462, - // "updateTime": 1676083034462, - // "status": "ACCEPTED", - // "avgPrice": "0", - // "source": "API", - // "clientOrderId": "", - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT", - // "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"}, - // "mmp": false - // } - // { - // cancelOrders/createOrders - // "code": -4005, - // "msg": "Quantity greater than max quantity." - // }, - // - const code = this.safeString (order, 'code'); - if (code !== undefined) { - // cancelOrders/createOrders might have a partial success - return this.safeOrder ({ 'info': order, 'status': 'rejected' }, market); - } - const status = this.parseOrderStatus (this.safeString (order, 'status')); - const marketId = this.safeString (order, 'symbol'); - const marketType = ('closePosition' in order) ? 'contract' : 'spot'; - const symbol = this.safeSymbol (marketId, market, undefined, marketType); - const filled = this.safeString (order, 'executedQty', '0'); - const timestamp = this.safeIntegerN (order, [ 'time', 'createTime', 'workingTime', 'transactTime', 'updateTime' ]); // order of the keys matters here - let lastTradeTimestamp = undefined; - if (('transactTime' in order) || ('updateTime' in order)) { - const timestampValue = this.safeInteger2 (order, 'updateTime', 'transactTime'); - if (status === 'open') { - if (Precise.stringGt (filled, '0')) { - lastTradeTimestamp = timestampValue; - } - } else if (status === 'closed') { - lastTradeTimestamp = timestampValue; - } - } - const lastUpdateTimestamp = this.safeInteger2 (order, 'transactTime', 'updateTime'); - const average = this.safeString (order, 'avgPrice'); - const price = this.safeString (order, 'price'); - const amount = this.safeString2 (order, 'origQty', 'quantity'); - // - Spot/Margin market: cummulativeQuoteQty - // - Futures market: cumQuote. - // Note this is not the actual cost, since Binance futures uses leverage to calculate margins. - let cost = this.safeString2 (order, 'cummulativeQuoteQty', 'cumQuote'); - cost = this.safeString (order, 'cumBase', cost); - const id = this.safeString (order, 'orderId'); - let type = this.safeStringLower (order, 'type'); - const side = this.safeStringLower (order, 'side'); - const fills = this.safeValue (order, 'fills', []); - const clientOrderId = this.safeString (order, 'clientOrderId'); - let timeInForce = this.safeString (order, 'timeInForce'); - if (timeInForce === 'GTX') { - // GTX means "Good Till Crossing" and is an equivalent way of saying Post Only - timeInForce = 'PO'; - } - const postOnly = (type === 'limit_maker') || (timeInForce === 'PO'); - if (type === 'limit_maker') { - type = 'limit'; - } - const stopPriceString = this.safeString (order, 'stopPrice'); - const stopPrice = this.parseNumber (this.omitZero (stopPriceString)); - return this.safeOrder ({ - 'info': order, - 'id': id, - 'clientOrderId': clientOrderId, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'lastTradeTimestamp': lastTradeTimestamp, - 'lastUpdateTimestamp': lastUpdateTimestamp, - 'symbol': symbol, - 'type': type, - 'timeInForce': timeInForce, - 'postOnly': postOnly, - 'reduceOnly': this.safeValue (order, 'reduceOnly'), - 'side': side, - 'price': price, - 'triggerPrice': stopPrice, - 'amount': amount, - 'cost': cost, - 'average': average, - 'filled': filled, - 'remaining': undefined, - 'status': status, - 'fee': { - 'currency': this.safeString (order, 'quoteAsset'), - 'cost': this.safeNumber (order, 'fee'), - 'rate': undefined, - }, - 'trades': fills, - }, market); - } - - async createOrders (orders: OrderRequest[], params = {}) { - /** - * @method - * @name binance#createOrders - * @description *contract only* create a list of trade orders - * @see https://binance-docs.github.io/apidocs/futures/en/#place-multiple-orders-trade - * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params - * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - await this.loadMarkets (); - const ordersRequests = []; - let orderSymbols = []; - for (let i = 0; i < orders.length; i++) { - const rawOrder = orders[i]; - const marketId = this.safeString (rawOrder, 'symbol'); - orderSymbols.push (marketId); - const type = this.safeString (rawOrder, 'type'); - const side = this.safeString (rawOrder, 'side'); - const amount = this.safeValue (rawOrder, 'amount'); - const price = this.safeValue (rawOrder, 'price'); - const orderParams = this.safeValue (rawOrder, 'params', {}); - const orderRequest = this.createOrderRequest (marketId, type, side, amount, price, orderParams); - ordersRequests.push (orderRequest); - } - orderSymbols = this.marketSymbols (orderSymbols, undefined, false, true, true); - const market = this.market (orderSymbols[0]); - if (market['spot']) { - throw new NotSupported (this.id + ' createOrders() does not support ' + market['type'] + ' orders'); - } - let response = undefined; - let request = { - 'batchOrders': ordersRequests, - }; - request = this.extend (request, params); - if (market['linear']) { - response = await this.fapiPrivatePostBatchOrders (request); - } else if (market['option']) { - response = await this.eapiPrivatePostBatchOrders (request); - } else { - response = await this.dapiPrivatePostBatchOrders (request); - } - // - // [ - // { - // "code": -4005, - // "msg": "Quantity greater than max quantity." - // }, - // { - // "orderId": 650640530, - // "symbol": "LTCUSDT", - // "status": "NEW", - // "clientOrderId": "x-xcKtGhcu32184eb13585491289bbaf", - // "price": "54.00", - // "avgPrice": "0.00", - // "origQty": "0.100", - // "executedQty": "0.000", - // "cumQty": "0.000", - // "cumQuote": "0.00000", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "BUY", - // "positionSide": "BOTH", - // "stopPrice": "0.00", - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, - // "origType": "LIMIT", - // "priceMatch": "NONE", - // "selfTradePreventionMode": "NONE", - // "goodTillDate": 0, - // "updateTime": 1698073926929 - // } - // ] - // - return this.parseOrders (response); - } - - async createOrder (symbol: string, type: OrderType, side: OrderSide, amount, price = undefined, params = {}) { - /** - * @method - * @name binance#createOrder - * @description create a trade order - * @see https://binance-docs.github.io/apidocs/spot/en/#new-order-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#test-new-order-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#new-order-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#new-order-trade - * @see https://binance-docs.github.io/apidocs/voptions/en/#new-order-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#new-order-using-sor-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#test-new-order-using-sor-trade - * @param {string} symbol unified symbol of the market to create an order in - * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' - * @param {string} side 'buy' or 'sell' - * @param {float} amount how much of currency you want to trade in units of base currency - * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @param {boolean} [params.sor] *spot only* whether to use SOR (Smart Order Routing) or not, default is false - * @param {boolean} [params.test] *spot only* whether to use the test endpoint or not, default is false - * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - const marketType = this.safeString (params, 'type', market['type']); - const [ marginMode, query ] = this.handleMarginModeAndParams ('createOrder', params); - const sor = this.safeValue2 (params, 'sor', 'SOR', false); - params = this.omit (params, 'sor', 'SOR'); - const request = this.createOrderRequest (symbol, type, side, amount, price, params); - let method = 'privatePostOrder'; - if (sor) { - method = 'privatePostSorOrder'; - } else if (market['linear']) { - method = 'fapiPrivatePostOrder'; - } else if (market['inverse']) { - method = 'dapiPrivatePostOrder'; - } else if (marketType === 'margin' || marginMode !== undefined) { - method = 'sapiPostMarginOrder'; - } - if (market['option']) { - method = 'eapiPrivatePostOrder'; - } - // support for testing orders - if (market['spot'] || marketType === 'margin') { - const test = this.safeValue (query, 'test', false); - if (test) { - method += 'Test'; - } - } - const response = await this[method] (request); - return this.parseOrder (response, market); - } - - createOrderRequest (symbol: string, type: OrderType, side: OrderSide, amount, price = undefined, params = {}) { - /** - * @method - * @ignore - * @name binance#createOrderRequest - * @description helper function to build request - * @param {string} symbol unified symbol of the market to create an order in - * @param {string} type 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP' - * @param {string} side 'buy' or 'sell' - * @param {float} amount how much of currency you want to trade in units of base currency - * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders - * @param {object} params extra parameters specific to the exchange API endpoint - * @param {string|undefined} params.marginMode 'cross' or 'isolated', for spot margin trading - * @returns {object} request to be sent to the exchange - */ - const market = this.market (symbol); - const marketType = this.safeString (params, 'type', market['type']); - const clientOrderId = this.safeString2 (params, 'newClientOrderId', 'clientOrderId'); - const initialUppercaseType = type.toUpperCase (); - const isMarketOrder = initialUppercaseType === 'MARKET'; - const isLimitOrder = initialUppercaseType === 'LIMIT'; - const postOnly = this.isPostOnly (isMarketOrder, initialUppercaseType === 'LIMIT_MAKER', params); - const triggerPrice = this.safeValue2 (params, 'triggerPrice', 'stopPrice'); - const stopLossPrice = this.safeValue (params, 'stopLossPrice', triggerPrice); // fallback to stopLoss - const takeProfitPrice = this.safeValue (params, 'takeProfitPrice'); - const trailingDelta = this.safeValue (params, 'trailingDelta'); - const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined; - const isTakeProfit = takeProfitPrice !== undefined; - params = this.omit (params, [ 'type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice' ]); - const [ marginMode, query ] = this.handleMarginModeAndParams ('createOrder', params); - const request = { - 'symbol': market['id'], - 'side': side.toUpperCase (), - }; - if (market['spot'] || marketType === 'margin') { - // only supported for spot/margin api (all margin markets are spot markets) - if (postOnly) { - type = 'LIMIT_MAKER'; - } - } - if (marketType === 'margin' || marginMode !== undefined) { - const reduceOnly = this.safeValue (params, 'reduceOnly'); - if (reduceOnly) { - request['sideEffectType'] = 'AUTO_REPAY'; - params = this.omit (params, 'reduceOnly'); - } - } - let uppercaseType = type.toUpperCase (); - let stopPrice = undefined; - if (isStopLoss) { - stopPrice = stopLossPrice; - if (isMarketOrder) { - // spot STOP_LOSS market orders are not a valid order type - uppercaseType = market['contract'] ? 'STOP_MARKET' : 'STOP_LOSS'; - } else if (isLimitOrder) { - uppercaseType = market['contract'] ? 'STOP' : 'STOP_LOSS_LIMIT'; - } - } else if (isTakeProfit) { - stopPrice = takeProfitPrice; - if (isMarketOrder) { - // spot TAKE_PROFIT market orders are not a valid order type - uppercaseType = market['contract'] ? 'TAKE_PROFIT_MARKET' : 'TAKE_PROFIT'; - } else if (isLimitOrder) { - uppercaseType = market['contract'] ? 'TAKE_PROFIT' : 'TAKE_PROFIT_LIMIT'; - } - } - if (marginMode === 'isolated') { - request['isIsolated'] = true; - } - if (clientOrderId === undefined) { - const broker = this.safeValue (this.options, 'broker', {}); - const defaultId = (market['contract']) ? 'x-xcKtGhcu' : 'x-R4BD3S82'; - const brokerId = this.safeString (broker, marketType, defaultId); - request['newClientOrderId'] = brokerId + this.uuid22 (); - } else { - request['newClientOrderId'] = clientOrderId; - } - if ((marketType === 'spot') || (marketType === 'margin')) { - request['newOrderRespType'] = this.safeValue (this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills - } else { - // swap, futures and options - request['newOrderRespType'] = 'RESULT'; // "ACK", "RESULT", default "ACK" - } - if (market['option']) { - if (type === 'market') { - throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market'); - } - } else { - const validOrderTypes = this.safeValue (market['info'], 'orderTypes'); - if (!this.inArray (uppercaseType, validOrderTypes)) { - if (initialUppercaseType !== uppercaseType) { - throw new InvalidOrder (this.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders'); - } else { - throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market'); - } - } - } - request['type'] = uppercaseType; - // additional required fields depending on the order type - let timeInForceIsRequired = false; - let priceIsRequired = false; - let stopPriceIsRequired = false; - let quantityIsRequired = false; - // - // spot/margin - // - // LIMIT timeInForce, quantity, price - // MARKET quantity or quoteOrderQty - // STOP_LOSS quantity, stopPrice - // STOP_LOSS_LIMIT timeInForce, quantity, price, stopPrice - // TAKE_PROFIT quantity, stopPrice - // TAKE_PROFIT_LIMIT timeInForce, quantity, price, stopPrice - // LIMIT_MAKER quantity, price - // - // futures - // - // LIMIT timeInForce, quantity, price - // MARKET quantity - // STOP/TAKE_PROFIT quantity, price, stopPrice - // STOP_MARKET stopPrice - // TAKE_PROFIT_MARKET stopPrice - // TRAILING_STOP_MARKET callbackRate - // - if (uppercaseType === 'MARKET') { - if (market['spot']) { - const quoteOrderQty = this.safeValue (this.options, 'quoteOrderQty', true); - if (quoteOrderQty) { - const quoteOrderQtyNew = this.safeValue2 (query, 'quoteOrderQty', 'cost'); - const precision = market['precision']['price']; - if (quoteOrderQtyNew !== undefined) { - request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQtyNew, TRUNCATE, precision, this.precisionMode); - } else if (price !== undefined) { - const amountString = this.numberToString (amount); - const priceString = this.numberToString (price); - const quoteOrderQuantity = Precise.stringMul (amountString, priceString); - request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQuantity, TRUNCATE, precision, this.precisionMode); - } else { - quantityIsRequired = true; - } - } else { - quantityIsRequired = true; - } - } else { - quantityIsRequired = true; - } - } else if (uppercaseType === 'LIMIT') { - priceIsRequired = true; - timeInForceIsRequired = true; - quantityIsRequired = true; - } else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) { - stopPriceIsRequired = true; - quantityIsRequired = true; - if (market['linear'] || market['inverse']) { - priceIsRequired = true; - } - } else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) { - quantityIsRequired = true; - stopPriceIsRequired = true; - priceIsRequired = true; - timeInForceIsRequired = true; - } else if (uppercaseType === 'LIMIT_MAKER') { - priceIsRequired = true; - quantityIsRequired = true; - } else if (uppercaseType === 'STOP') { - quantityIsRequired = true; - stopPriceIsRequired = true; - priceIsRequired = true; - } else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) { - const closePosition = this.safeValue (query, 'closePosition'); - if (closePosition === undefined) { - quantityIsRequired = true; - } - stopPriceIsRequired = true; - } else if (uppercaseType === 'TRAILING_STOP_MARKET') { - quantityIsRequired = true; - const callbackRate = this.safeNumber (query, 'callbackRate'); - if (callbackRate === undefined) { - throw new InvalidOrder (this.id + ' createOrder() requires a callbackRate extra param for a ' + type + ' order'); - } - } - if (quantityIsRequired) { - request['quantity'] = this.amountToPrecision (symbol, amount); - } - if (priceIsRequired) { - if (price === undefined) { - throw new InvalidOrder (this.id + ' createOrder() requires a price argument for a ' + type + ' order'); - } - request['price'] = this.priceToPrecision (symbol, price); - } - if (timeInForceIsRequired) { - request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel - } - if (market['contract'] && postOnly) { - request['timeInForce'] = 'GTX'; - } - if (stopPriceIsRequired) { - if (market['contract']) { - if (stopPrice === undefined) { - throw new InvalidOrder (this.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order'); - } - } else { - // check for delta price as well - if (trailingDelta === undefined && stopPrice === undefined) { - throw new InvalidOrder (this.id + ' createOrder() requires a stopPrice or trailingDelta param for a ' + type + ' order'); - } - } - if (stopPrice !== undefined) { - request['stopPrice'] = this.priceToPrecision (symbol, stopPrice); - } - } - // remove timeInForce from params because PO is only used by this.isPostOnly and it's not a valid value for Binance - if (this.safeString (params, 'timeInForce') === 'PO') { - params = this.omit (params, [ 'timeInForce' ]); - } - const requestParams = this.omit (params, [ 'quoteOrderQty', 'cost', 'stopPrice', 'test', 'type', 'newClientOrderId', 'clientOrderId', 'postOnly' ]); - return this.extend (request, requestParams); - } - - async fetchOrder (id: string, symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#fetchOrder - * @description fetches information on an order made by the user - * @see https://binance-docs.github.io/apidocs/spot/en/#query-order-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#query-order-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#query-order-user_data - * @see https://binance-docs.github.io/apidocs/voptions/en/#query-single-order-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-order-user_data - * @param {string} symbol unified symbol of the market the order was made in - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', 'spot'); - const type = this.safeString (params, 'type', defaultType); - const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchOrder', params); - const request = { - 'symbol': market['id'], - }; - let method = 'privateGetOrder'; - if (market['option']) { - method = 'eapiPrivateGetOrder'; - } else if (market['linear']) { - method = 'fapiPrivateGetOrder'; - } else if (market['inverse']) { - method = 'dapiPrivateGetOrder'; - } else if (type === 'margin' || marginMode !== undefined) { - method = 'sapiGetMarginOrder'; - if (marginMode === 'isolated') { - request['isIsolated'] = true; - } - } - const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); - if (clientOrderId !== undefined) { - if (market['option']) { - request['clientOrderId'] = clientOrderId; - } else { - request['origClientOrderId'] = clientOrderId; - } - } else { - request['orderId'] = id; - } - const requestParams = this.omit (query, [ 'type', 'clientOrderId', 'origClientOrderId' ]); - const response = await this[method] (this.extend (request, requestParams)); - return this.parseOrder (response, market); - } - - async fetchOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchOrders - * @description fetches information on multiple orders made by the user - * @see https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-orders-user_data - * @param {string} symbol unified market symbol of the market orders were made in - * @param {int} [since] the earliest time in ms to fetch orders for - * @param {int} [limit] the maximum number of order structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @param {int} [params.until] the latest time in ms to fetch orders for - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument'); - } - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchOrders', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchOrders', symbol, since, limit, params) as Order[]; - } - const market = this.market (symbol); - const defaultType = this.safeString2 (this.options, 'fetchOrders', 'defaultType', 'spot'); - const type = this.safeString (params, 'type', defaultType); - const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchOrders', params); - const request = { - 'symbol': market['id'], - }; - let method = 'privateGetAllOrders'; - if (market['option']) { - method = 'eapiPrivateGetHistoryOrders'; - } else if (market['linear']) { - method = 'fapiPrivateGetAllOrders'; - } else if (market['inverse']) { - method = 'dapiPrivateGetAllOrders'; - } else if (type === 'margin' || marginMode !== undefined) { - method = 'sapiGetMarginAllOrders'; - if (marginMode === 'isolated') { - request['isIsolated'] = true; - } - } - const until = this.safeInteger (params, 'until'); - if (until !== undefined) { - params = this.omit (params, 'until'); - request['endTime'] = until; - } - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['limit'] = limit; - } - const response = await this[method] (this.extend (request, query)); - // - // spot - // - // [ - // { - // "symbol": "LTCBTC", - // "orderId": 1, - // "clientOrderId": "myOrder1", - // "price": "0.1", - // "origQty": "1.0", - // "executedQty": "0.0", - // "cummulativeQuoteQty": "0.0", - // "status": "NEW", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY", - // "stopPrice": "0.0", - // "icebergQty": "0.0", - // "time": 1499827319559, - // "updateTime": 1499827319559, - // "isWorking": true - // } - // ] - // - // futures - // - // [ - // { - // "symbol": "BTCUSDT", - // "orderId": 1, - // "clientOrderId": "myOrder1", - // "price": "0.1", - // "origQty": "1.0", - // "executedQty": "1.0", - // "cumQuote": "10.0", - // "status": "NEW", - // "timeInForce": "GTC", - // "type": "LIMIT", - // "side": "BUY", - // "stopPrice": "0.0", - // "updateTime": 1499827319559 - // } - // ] - // - // options - // - // [ - // { - // "orderId": 4728833085436977152, - // "symbol": "ETH-230211-1500-C", - // "price": "10.0", - // "quantity": "1.00", - // "executedQty": "0.00", - // "fee": "0", - // "side": "BUY", - // "type": "LIMIT", - // "timeInForce": "GTC", - // "reduceOnly": false, - // "postOnly": false, - // "createTime": 1676083034462, - // "updateTime": 1676083034462, - // "status": "ACCEPTED", - // "avgPrice": "0", - // "source": "API", - // "clientOrderId": "", - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT", - // "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"}, - // "mmp": false - // } - // ] - // - return this.parseOrders (response, market, since, limit); - } - - async fetchOpenOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchOpenOrders - * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data - * @see https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data - * @description fetch all unfilled currently open orders - * @see https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data - * @see https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-orders-user_data - * @param {string} symbol unified market symbol - * @param {int} [since] the earliest time in ms to fetch open orders for - * @param {int} [limit] the maximum number of open orders structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - await this.loadMarkets (); - let market = undefined; - let type = undefined; - const request = {}; - let marginMode = undefined; - let query = undefined; - [ marginMode, query ] = this.handleMarginModeAndParams ('fetchOpenOrders', params); - if (symbol !== undefined) { - market = this.market (symbol); - request['symbol'] = market['id']; - const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot'); - const marketType = ('type' in market) ? market['type'] : defaultType; - type = this.safeString (query, 'type', marketType); - } else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) { - const symbols = this.symbols; - const numSymbols = symbols.length; - const fetchOpenOrdersRateLimit = this.parseToInt (numSymbols / 2); - throw new ExchangeError (this.id + ' fetchOpenOrders() WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + fetchOpenOrdersRateLimit.toString () + ' seconds. Do not call this method frequently to avoid ban. Set ' + this.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = false to suppress this warning message.'); - } else { - const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot'); - type = this.safeString (query, 'type', defaultType); - } - let subType = undefined; - [ subType, query ] = this.handleSubTypeAndParams ('fetchOpenOrders', market, query); - const requestParams = this.omit (query, 'type'); - let method = 'privateGetOpenOrders'; - if (type === 'option') { - method = 'eapiPrivateGetOpenOrders'; - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['limit'] = limit; - } - } else if (this.isLinear (type, subType)) { - method = 'fapiPrivateGetOpenOrders'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateGetOpenOrders'; - } else if (type === 'margin' || marginMode !== undefined) { - method = 'sapiGetMarginOpenOrders'; - if (marginMode === 'isolated') { - request['isIsolated'] = true; - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument for isolated markets'); - } - } - } - const response = await this[method] (this.extend (request, requestParams)); - return this.parseOrders (response, market, since, limit); - } - - async fetchClosedOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchClosedOrders - * @description fetches information on multiple closed orders made by the user - * @see https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-orders-user_data - * @param {string} symbol unified market symbol of the market orders were made in - * @param {int} [since] the earliest time in ms to fetch orders for - * @param {int} [limit] the maximum number of order structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - const orders = await this.fetchOrders (symbol, since, limit, params); - return this.filterBy (orders, 'status', 'closed') as Order[]; - } - - async fetchCanceledOrders (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchCanceledOrders - * @description fetches information on multiple canceled orders made by the user - * @see https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-orders-user_data - * @see https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade - * @param {string} symbol unified market symbol of the market the orders were made in - * @param {int} [since] the earliest time in ms to fetch orders for - * @param {int} [limit] the maximum number of order structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchCanceledOrders() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - if (market['swap'] || market['future']) { - throw new NotSupported (this.id + ' fetchCanceledOrders() supports spot, margin and option markets only'); - } - params = this.omit (params, 'type'); - const orders = await this.fetchOrders (symbol, since, undefined, params); - const filteredOrders = this.filterBy (orders, 'status', 'canceled'); - return this.filterByLimit (filteredOrders, limit); - } - - async cancelOrder (id: string, symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#cancelOrder - * @description cancels an open order - * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-order-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-order-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-order-trade - * @see https://binance-docs.github.io/apidocs/voptions/en/#cancel-option-order-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade - * @param {string} id order id - * @param {string} symbol unified symbol of the market the order was made in - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const defaultType = this.safeString2 (this.options, 'cancelOrder', 'defaultType', 'spot'); - const type = this.safeString (params, 'type', defaultType); - const [ marginMode, query ] = this.handleMarginModeAndParams ('cancelOrder', params); - const request = { - 'symbol': market['id'], - // 'orderId': id, - // 'origClientOrderId': id, - }; - const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId'); - if (clientOrderId !== undefined) { - if (market['option']) { - request['clientOrderId'] = clientOrderId; - } else { - request['origClientOrderId'] = clientOrderId; - } - } else { - request['orderId'] = id; - } - let method = 'privateDeleteOrder'; - if (market['option']) { - method = 'eapiPrivateDeleteOrder'; - } else if (market['linear']) { - method = 'fapiPrivateDeleteOrder'; - } else if (market['inverse']) { - method = 'dapiPrivateDeleteOrder'; - } else if (type === 'margin' || marginMode !== undefined) { - method = 'sapiDeleteMarginOrder'; - if (marginMode === 'isolated') { - request['isIsolated'] = true; - } - } - const requestParams = this.omit (query, [ 'type', 'origClientOrderId', 'clientOrderId' ]); - const response = await this[method] (this.extend (request, requestParams)); - return this.parseOrder (response, market); - } - - async cancelAllOrders (symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#cancelAllOrders - * @see https://binance-docs.github.io/apidocs/spot/en/#cancel-all-open-orders-on-a-symbol-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-all-open-orders-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-all-open-orders-trade - * @see https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-on-specific-symbol-trade - * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade - * @description cancel all open orders in a market - * @param {string} symbol unified market symbol of the market to cancel orders in - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {string} [params.marginMode] 'cross' or 'isolated', for spot margin trading - * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - const type = this.safeString (params, 'type', market['type']); - params = this.omit (params, [ 'type' ]); - const [ marginMode, query ] = this.handleMarginModeAndParams ('cancelAllOrders', params); - let method = 'privateDeleteOpenOrders'; - if (market['option']) { - method = 'eapiPrivateDeleteAllOpenOrders'; - } else if (market['linear']) { - method = 'fapiPrivateDeleteAllOpenOrders'; - } else if (market['inverse']) { - method = 'dapiPrivateDeleteAllOpenOrders'; - } else if ((type === 'margin') || (marginMode !== undefined)) { - method = 'sapiDeleteMarginOpenOrders'; - if (marginMode === 'isolated') { - request['isIsolated'] = true; - } - } - const response = await this[method] (this.extend (request, query)); - if (Array.isArray (response)) { - return this.parseOrders (response, market); - } else { - return response; - } - } - - async cancelOrders (ids: Int[], symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#cancelOrders - * @description cancel multiple orders - * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-multiple-orders-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#cancel-multiple-orders-trade - * @param {string[]} ids order ids - * @param {string} [symbol] unified market symbol - * @param {object} [params] extra parameters specific to the exchange API endpoint - * - * EXCHANGE SPECIFIC PARAMETERS - * @param {string[]} [params.origClientOrderIdList] max length 10 e.g. ["my_id_1","my_id_2"], encode the double quotes. No space after comma - * @param {int[]} [params.recvWindow] - * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' cancelOrders() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - if (!market['contract']) { - throw new BadRequest (this.id + ' cancelOrders is only supported for swap markets.'); - } - const request = { - 'symbol': market['id'], - 'orderidlist': ids, - }; - let response = undefined; - if (market['linear']) { - response = await this.fapiPrivateDeleteBatchOrders (this.extend (request, params)); - } else if (market['inverse']) { - response = await this.dapiPrivateDeleteBatchOrders (this.extend (request, params)); - } - // - // [ - // { - // "clientOrderId": "myOrder1", - // "cumQty": "0", - // "cumQuote": "0", - // "executedQty": "0", - // "orderId": 283194212, - // "origQty": "11", - // "origType": "TRAILING_STOP_MARKET", - // "price": "0", - // "reduceOnly": false, - // "side": "BUY", - // "positionSide": "SHORT", - // "status": "CANCELED", - // "stopPrice": "9300", // please ignore when order type is TRAILING_STOP_MARKET - // "closePosition": false, // if Close-All - // "symbol": "BTCUSDT", - // "timeInForce": "GTC", - // "type": "TRAILING_STOP_MARKET", - // "activatePrice": "9020", // activation price, only return with TRAILING_STOP_MARKET order - // "priceRate": "0.3", // callback rate, only return with TRAILING_STOP_MARKET order - // "updateTime": 1571110484038, - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, // if conditional order trigger is protected - // "priceMatch": "NONE", // price match mode - // "selfTradePreventionMode": "NONE", // self trading preventation mode - // "goodTillDate": 0 // order pre-set auot cancel time for TIF GTD order - // }, - // { - // "code": -2011, - // "msg": "Unknown order sent." - // } - // ] - // - return this.parseOrders (response, market); - } - - async fetchOrderTrades (id: string, symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchOrderTrades - * @description fetch all the trades made from a single order - * @see https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#account-trade-list-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-trade-list-user_data - * @param {string} id order id - * @param {string} symbol unified market symbol - * @param {int} [since] the earliest time in ms to fetch trades for - * @param {int} [limit] the maximum number of trades to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchOrderTrades() requires a symbol argument'); - } - await this.loadMarkets (); - const market = this.market (symbol); - const type = this.safeString (params, 'type', market['type']); - params = this.omit (params, 'type'); - if (type !== 'spot') { - throw new NotSupported (this.id + ' fetchOrderTrades() supports spot markets only'); - } - const request = { - 'orderId': id, - }; - return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params)); - } - - async fetchMyTrades (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchMyTrades - * @description fetch all trades made by the user - * @see https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#account-trade-list-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-trade-list-user_data - * @param {string} symbol unified market symbol - * @param {int} [since] the earliest time in ms to fetch trades for - * @param {int} [limit] the maximum number of trades structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @param {int} [params.until] the latest time in ms to fetch entries for - * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchMyTrades', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchMyTrades', symbol, since, limit, params) as Trade[]; - } - const request = {}; - let market = undefined; - let type = undefined; - let method = undefined; - let marginMode = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbol'] = market['id']; - } - [ type, params ] = this.handleMarketTypeAndParams ('fetchMyTrades', market, params); - if (type === 'option') { - method = 'eapiPrivateGetUserTrades'; - } else { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument'); - } - [ marginMode, params ] = this.handleMarginModeAndParams ('fetchMyTrades', params); - if (type === 'spot' || type === 'margin') { - method = 'privateGetMyTrades'; - if ((type === 'margin') || (marginMode !== undefined)) { - method = 'sapiGetMarginMyTrades'; - if (marginMode === 'isolated') { - request['isIsolated'] = true; - } - } - } else if (market['linear']) { - method = 'fapiPrivateGetUserTrades'; - } else if (market['inverse']) { - method = 'dapiPrivateGetUserTrades'; - } - } - let endTime = this.safeInteger2 (params, 'until', 'endTime'); - if (since !== undefined) { - const startTime = since; - request['startTime'] = startTime; - // https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data - // If startTime and endTime are both not sent, then the last 7 days' data will be returned. - // The time between startTime and endTime cannot be longer than 7 days. - // The parameter fromId cannot be sent with startTime or endTime. - const currentTimestamp = this.milliseconds (); - const oneWeek = 7 * 24 * 60 * 60 * 1000; - if ((currentTimestamp - startTime) >= oneWeek) { - if ((endTime === undefined) && market['linear']) { - endTime = this.sum (startTime, oneWeek); - endTime = Math.min (endTime, currentTimestamp); - } - } - } - if (endTime !== undefined) { - request['endTime'] = endTime; - params = this.omit (params, [ 'endTime', 'until' ]); - } - if (limit !== undefined) { - if ((type === 'option') || market['contract']) { - limit = Math.min (limit, 1000); // above 1000, returns error - } - request['limit'] = limit; - } - const response = await this[method] (this.extend (request, params)); - // - // spot trade - // - // [ - // { - // "symbol": "BNBBTC", - // "id": 28457, - // "orderId": 100234, - // "price": "4.00000100", - // "qty": "12.00000000", - // "commission": "10.10000000", - // "commissionAsset": "BNB", - // "time": 1499865549590, - // "isBuyer": true, - // "isMaker": false, - // "isBestMatch": true, - // } - // ] - // - // futures trade - // - // [ - // { - // "accountId": 20, - // "buyer": False, - // "commission": "-0.07819010", - // "commissionAsset": "USDT", - // "counterPartyId": 653, - // "id": 698759, - // "maker": False, - // "orderId": 25851813, - // "price": "7819.01", - // "qty": "0.002", - // "quoteQty": "0.01563", - // "realizedPnl": "-0.91539999", - // "side": "SELL", - // "symbol": "BTCUSDT", - // "time": 1569514978020 - // } - // ] - // - // options (eapi) - // - // [ - // { - // "id": 1125899906844226012, - // "tradeId": 73, - // "orderId": 4638761100843040768, - // "symbol": "ETH-230211-1500-C", - // "price": "18.70000000", - // "quantity": "-0.57000000", - // "fee": "0.17305890", - // "realizedProfit": "-3.53400000", - // "side": "SELL", - // "type": "LIMIT", - // "volatility": "0.30000000", - // "liquidity": "MAKER", - // "time": 1676085216845, - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT" - // } - // ] - // - return this.parseTrades (response, market, since, limit); - } - - async fetchMyDustTrades (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchMyDustTrades - * @description fetch all dust trades made by the user - * @see https://binance-docs.github.io/apidocs/spot/en/#dustlog-user_data - * @param {string} symbol not used by binance fetchMyDustTrades () - * @param {int} [since] the earliest time in ms to fetch my dust trades for - * @param {int} [limit] the maximum number of dust trades to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} - */ - // - // Binance provides an opportunity to trade insignificant (i.e. non-tradable and non-withdrawable) - // token leftovers (of any asset) into `BNB` coin which in turn can be used to pay trading fees with it. - // The corresponding trades history is called the `Dust Log` and can be requested via the following end-point: - // https://github.com/binance-exchange/binance-official-api-docs/blob/master/wapi-api.md#dustlog-user_data - // - await this.loadMarkets (); - const request = {}; - if (since !== undefined) { - request['startTime'] = since; - request['endTime'] = this.sum (since, 7776000000); - } - const response = await this.sapiGetAssetDribblet (this.extend (request, params)); - // { - // "total": "4", - // "userAssetDribblets": [ - // { - // "operateTime": "1627575731000", - // "totalServiceChargeAmount": "0.00001453", - // "totalTransferedAmount": "0.00072693", - // "transId": "70899815863", - // "userAssetDribbletDetails": [ - // { - // "fromAsset": "LTC", - // "amount": "0.000006", - // "transferedAmount": "0.00000267", - // "serviceChargeAmount": "0.00000005", - // "operateTime": "1627575731000", - // "transId": "70899815863" - // }, - // { - // "fromAsset": "GBP", - // "amount": "0.15949157", - // "transferedAmount": "0.00072426", - // "serviceChargeAmount": "0.00001448", - // "operateTime": "1627575731000", - // "transId": "70899815863" - // } - // ] - // }, - // ] - // } - const results = this.safeValue (response, 'userAssetDribblets', []); - const rows = this.safeInteger (response, 'total', 0); - const data = []; - for (let i = 0; i < rows; i++) { - const logs = this.safeValue (results[i], 'userAssetDribbletDetails', []); - for (let j = 0; j < logs.length; j++) { - logs[j]['isDustTrade'] = true; - data.push (logs[j]); - } - } - const trades = this.parseTrades (data, undefined, since, limit); - return this.filterBySinceLimit (trades, since, limit); - } - - parseDustTrade (trade, market: Market = undefined) { - // - // { - // "fromAsset": "USDT", - // "amount": "0.009669", - // "transferedAmount": "0.00002992", - // "serviceChargeAmount": "0.00000059", - // "operateTime": "1628076010000", - // "transId": "71416578712", - // "isDustTrade": true - // } - // - const orderId = this.safeString (trade, 'transId'); - const timestamp = this.safeInteger (trade, 'operateTime'); - const currencyId = this.safeString (trade, 'fromAsset'); - const tradedCurrency = this.safeCurrencyCode (currencyId); - const bnb = this.currency ('BNB'); - const earnedCurrency = bnb['code']; - const applicantSymbol = earnedCurrency + '/' + tradedCurrency; - let tradedCurrencyIsQuote = false; - if (applicantSymbol in this.markets) { - tradedCurrencyIsQuote = true; - } - const feeCostString = this.safeString (trade, 'serviceChargeAmount'); - const fee = { - 'currency': earnedCurrency, - 'cost': this.parseNumber (feeCostString), - }; - let symbol = undefined; - let amountString = undefined; - let costString = undefined; - let side = undefined; - if (tradedCurrencyIsQuote) { - symbol = applicantSymbol; - amountString = this.safeString (trade, 'transferedAmount'); - costString = this.safeString (trade, 'amount'); - side = 'buy'; - } else { - symbol = tradedCurrency + '/' + earnedCurrency; - amountString = this.safeString (trade, 'amount'); - costString = this.safeString (trade, 'transferedAmount'); - side = 'sell'; - } - let priceString = undefined; - if (costString !== undefined) { - if (amountString) { - priceString = Precise.stringDiv (costString, amountString); - } - } - const id = undefined; - const amount = this.parseNumber (amountString); - const price = this.parseNumber (priceString); - const cost = this.parseNumber (costString); - const type = undefined; - const takerOrMaker = undefined; - return { - 'id': id, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'symbol': symbol, - 'order': orderId, - 'type': type, - 'takerOrMaker': takerOrMaker, - 'side': side, - 'amount': amount, - 'price': price, - 'cost': cost, - 'fee': fee, - 'info': trade, - }; - } - - async fetchDeposits (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchDeposits - * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data - * @description fetch all deposits made to an account - * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#deposit-history-supporting-network-user_data - * @param {string} code unified currency code - * @param {int} [since] the earliest time in ms to fetch deposits for - * @param {int} [limit] the maximum number of deposits structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {bool} [params.fiat] if true, only fiat deposits will be returned - * @param {int} [params.until] the latest time in ms to fetch entries for - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchDeposits', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchDeposits', code, since, limit, params); - } - let currency = undefined; - let response = undefined; - const request = {}; - const legalMoney = this.safeValue (this.options, 'legalMoney', {}); - const fiatOnly = this.safeValue (params, 'fiat', false); - params = this.omit (params, 'fiatOnly'); - const until = this.safeInteger (params, 'until'); - params = this.omit (params, 'until'); - if (fiatOnly || (code in legalMoney)) { - if (code !== undefined) { - currency = this.currency (code); - } - request['transactionType'] = 0; - if (since !== undefined) { - request['beginTime'] = since; - } - if (until !== undefined) { - request['endTime'] = until; - } - const raw = await this.sapiGetFiatOrders (this.extend (request, params)); - response = this.safeValue (raw, 'data'); - // { - // "code": "000000", - // "message": "success", - // "data": [ - // { - // "orderNo": "25ced37075c1470ba8939d0df2316e23", - // "fiatCurrency": "EUR", - // "indicatedAmount": "15.00", - // "amount": "15.00", - // "totalFee": "0.00", - // "method": "card", - // "status": "Failed", - // "createTime": 1627501026000, - // "updateTime": 1627501027000 - // } - // ], - // "total": 1, - // "success": true - // } - } else { - if (code !== undefined) { - currency = this.currency (code); - request['coin'] = currency['id']; - } - if (since !== undefined) { - request['startTime'] = since; - // max 3 months range https://github.com/ccxt/ccxt/issues/6495 - let endTime = this.sum (since, 7776000000); - if (until !== undefined) { - endTime = Math.min (endTime, until); - } - request['endTime'] = endTime; - } - if (limit !== undefined) { - request['limit'] = limit; - } - response = await this.sapiGetCapitalDepositHisrec (this.extend (request, params)); - // [ - // { - // "amount": "0.01844487", - // "coin": "BCH", - // "network": "BCH", - // "status": 1, - // "address": "1NYxAJhW2281HK1KtJeaENBqHeygA88FzR", - // "addressTag": "", - // "txId": "bafc5902504d6504a00b7d0306a41154cbf1d1b767ab70f3bc226327362588af", - // "insertTime": 1610784980000, - // "transferType": 0, - // "confirmTimes": "2/2" - // }, - // { - // "amount": "4500", - // "coin": "USDT", - // "network": "BSC", - // "status": 1, - // "address": "0xc9c923c87347ca0f3451d6d308ce84f691b9f501", - // "addressTag": "", - // "txId": "Internal transfer 51376627901", - // "insertTime": 1618394381000, - // "transferType": 1, - // "confirmTimes": "1/15" - // } - // ] - } - for (let i = 0; i < response.length; i++) { - response[i]['type'] = 'deposit'; - } - return this.parseTransactions (response, currency, since, limit); - } - - async fetchWithdrawals (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}): Promise { - /** - * @method - * @name binance#fetchWithdrawals - * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data - * @description fetch all withdrawals made from an account - * @see https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data - * @param {string} code unified currency code - * @param {int} [since] the earliest time in ms to fetch withdrawals for - * @param {int} [limit] the maximum number of withdrawals structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {bool} [params.fiat] if true, only fiat withdrawals will be returned - * @param {int} [params.until] the latest time in ms to fetch withdrawals for - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchWithdrawals', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchWithdrawals', code, since, limit, params); - } - const legalMoney = this.safeValue (this.options, 'legalMoney', {}); - const fiatOnly = this.safeValue (params, 'fiat', false); - params = this.omit (params, 'fiatOnly'); - const request = {}; - const until = this.safeInteger (params, 'until'); - if (until !== undefined) { - params = this.omit (params, 'until'); - request['endTime'] = until; - } - let response = undefined; - let currency = undefined; - if (fiatOnly || (code in legalMoney)) { - if (code !== undefined) { - currency = this.currency (code); - } - request['transactionType'] = 1; - if (since !== undefined) { - request['beginTime'] = since; - } - const raw = await this.sapiGetFiatOrders (this.extend (request, params)); - response = this.safeValue (raw, 'data'); - // { - // "code": "000000", - // "message": "success", - // "data": [ - // { - // "orderNo": "CJW706452266115170304", - // "fiatCurrency": "GBP", - // "indicatedAmount": "10001.50", - // "amount": "100.00", - // "totalFee": "1.50", - // "method": "bank transfer", - // "status": "Successful", - // "createTime": 1620037745000, - // "updateTime": 1620038480000 - // }, - // { - // "orderNo": "CJW706287492781891584", - // "fiatCurrency": "GBP", - // "indicatedAmount": "10001.50", - // "amount": "100.00", - // "totalFee": "1.50", - // "method": "bank transfer", - // "status": "Successful", - // "createTime": 1619998460000, - // "updateTime": 1619998823000 - // } - // ], - // "total": 39, - // "success": true - // } - } else { - if (code !== undefined) { - currency = this.currency (code); - request['coin'] = currency['id']; - } - if (since !== undefined) { - request['startTime'] = since; - // max 3 months range https://github.com/ccxt/ccxt/issues/6495 - request['endTime'] = this.sum (since, 7776000000); - } - if (limit !== undefined) { - request['limit'] = limit; - } - response = await this.sapiGetCapitalWithdrawHistory (this.extend (request, params)); - // [ - // { - // "id": "69e53ad305124b96b43668ceab158a18", - // "amount": "28.75", - // "transactionFee": "0.25", - // "coin": "XRP", - // "status": 6, - // "address": "r3T75fuLjX51mmfb5Sk1kMNuhBgBPJsjza", - // "addressTag": "101286922", - // "txId": "19A5B24ED0B697E4F0E9CD09FCB007170A605BC93C9280B9E6379C5E6EF0F65A", - // "applyTime": "2021-04-15 12:09:16", - // "network": "XRP", - // "transferType": 0 - // }, - // { - // "id": "9a67628b16ba4988ae20d329333f16bc", - // "amount": "20", - // "transactionFee": "20", - // "coin": "USDT", - // "status": 6, - // "address": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1", - // "txId": "0x77fbf2cf2c85b552f0fd31fd2e56dc95c08adae031d96f3717d8b17e1aea3e46", - // "applyTime": "2021-04-15 12:06:53", - // "network": "ETH", - // "transferType": 0 - // }, - // { - // "id": "a7cdc0afbfa44a48bd225c9ece958fe2", - // "amount": "51", - // "transactionFee": "1", - // "coin": "USDT", - // "status": 6, - // "address": "TYDmtuWL8bsyjvcauUTerpfYyVhFtBjqyo", - // "txId": "168a75112bce6ceb4823c66726ad47620ad332e69fe92d9cb8ceb76023f9a028", - // "applyTime": "2021-04-13 12:46:59", - // "network": "TRX", - // "transferType": 0 - // } - // ] - } - for (let i = 0; i < response.length; i++) { - response[i]['type'] = 'withdrawal'; - } - return this.parseTransactions (response, currency, since, limit); - } - - parseTransactionStatusByType (status, type = undefined) { - const statusesByType = { - 'deposit': { - '0': 'pending', - '1': 'ok', - '6': 'ok', - // Fiat - // Processing, Failed, Successful, Finished, Refunding, Refunded, Refund Failed, Order Partial credit Stopped - 'Processing': 'pending', - 'Failed': 'failed', - 'Successful': 'ok', - 'Refunding': 'canceled', - 'Refunded': 'canceled', - 'Refund Failed': 'failed', - }, - 'withdrawal': { - '0': 'pending', // Email Sent - '1': 'canceled', // Cancelled (different from 1 = ok in deposits) - '2': 'pending', // Awaiting Approval - '3': 'failed', // Rejected - '4': 'pending', // Processing - '5': 'failed', // Failure - '6': 'ok', // Completed - // Fiat - // Processing, Failed, Successful, Finished, Refunding, Refunded, Refund Failed, Order Partial credit Stopped - 'Processing': 'pending', - 'Failed': 'failed', - 'Successful': 'ok', - 'Refunding': 'canceled', - 'Refunded': 'canceled', - 'Refund Failed': 'failed', - }, - }; - const statuses = this.safeValue (statusesByType, type, {}); - return this.safeString (statuses, status, status); - } - - parseTransaction (transaction, currency: Currency = undefined): Transaction { - // - // fetchDeposits - // - // { - // "amount": "4500", - // "coin": "USDT", - // "network": "BSC", - // "status": 1, - // "address": "0xc9c923c87347ca0f3451d6d308ce84f691b9f501", - // "addressTag": "", - // "txId": "Internal transfer 51376627901", - // "insertTime": 1618394381000, - // "transferType": 1, - // "confirmTimes": "1/15" - // } - // - // fetchWithdrawals - // - // { - // "id": "69e53ad305124b96b43668ceab158a18", - // "amount": "28.75", - // "transactionFee": "0.25", - // "coin": "XRP", - // "status": 6, - // "address": "r3T75fuLjX51mmfb5Sk1kMNuhBgBPJsjza", - // "addressTag": "101286922", - // "txId": "19A5B24ED0B697E4F0E9CD09FCB007170A605BC93C9280B9E6379C5E6EF0F65A", - // "applyTime": "2021-04-15 12:09:16", - // "network": "XRP", - // "transferType": 0 - // } - // - // fiat transaction - // withdraw - // { - // "orderNo": "CJW684897551397171200", - // "fiatCurrency": "GBP", - // "indicatedAmount": "29.99", - // "amount": "28.49", - // "totalFee": "1.50", - // "method": "bank transfer", - // "status": "Successful", - // "createTime": 1614898701000, - // "updateTime": 1614898820000 - // } - // - // deposit - // { - // "orderNo": "25ced37075c1470ba8939d0df2316e23", - // "fiatCurrency": "EUR", - // "transactionType": 0, - // "indicatedAmount": "15.00", - // "amount": "15.00", - // "totalFee": "0.00", - // "method": "card", - // "status": "Failed", - // "createTime": "1627501026000", - // "updateTime": "1627501027000" - // } - // - // withdraw - // - // { id: "9a67628b16ba4988ae20d329333f16bc" } - // - const id = this.safeString2 (transaction, 'id', 'orderNo'); - const address = this.safeString (transaction, 'address'); - let tag = this.safeString (transaction, 'addressTag'); // set but unused - if (tag !== undefined) { - if (tag.length < 1) { - tag = undefined; - } - } - let txid = this.safeString (transaction, 'txId'); - if ((txid !== undefined) && (txid.indexOf ('Internal transfer ') >= 0)) { - txid = txid.slice (18); - } - const currencyId = this.safeString2 (transaction, 'coin', 'fiatCurrency'); - let code = this.safeCurrencyCode (currencyId, currency); - let timestamp = undefined; - timestamp = this.safeInteger2 (transaction, 'insertTime', 'createTime'); - if (timestamp === undefined) { - timestamp = this.parse8601 (this.safeString (transaction, 'applyTime')); - } - const updated = this.safeInteger2 (transaction, 'successTime', 'updateTime'); - let type = this.safeString (transaction, 'type'); - if (type === undefined) { - const txType = this.safeString (transaction, 'transactionType'); - if (txType !== undefined) { - type = (txType === '0') ? 'deposit' : 'withdrawal'; - } - const legalMoneyCurrenciesById = this.safeValue (this.options, 'legalMoneyCurrenciesById'); - code = this.safeString (legalMoneyCurrenciesById, code, code); - } - const status = this.parseTransactionStatusByType (this.safeString (transaction, 'status'), type); - const amount = this.safeNumber (transaction, 'amount'); - const feeCost = this.safeNumber2 (transaction, 'transactionFee', 'totalFee'); - let fee = undefined; - if (feeCost !== undefined) { - fee = { 'currency': code, 'cost': feeCost }; - } - const internalInteger = this.safeInteger (transaction, 'transferType'); - let internal = undefined; - if (internalInteger !== undefined) { - internal = internalInteger ? true : false; - } - const network = this.safeString (transaction, 'network'); - return { - 'info': transaction, - 'id': id, - 'txid': txid, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'network': network, - 'address': address, - 'addressTo': address, - 'addressFrom': undefined, - 'tag': tag, - 'tagTo': tag, - 'tagFrom': undefined, - 'type': type, - 'amount': amount, - 'currency': code, - 'status': status, - 'updated': updated, - 'internal': internal, - 'comment': undefined, - 'fee': fee, - }; - } - - parseTransferStatus (status) { - const statuses = { - 'CONFIRMED': 'ok', - }; - return this.safeString (statuses, status, status); - } - - parseTransfer (transfer, currency: Currency = undefined) { - // - // transfer - // - // { - // "tranId":13526853623 - // } - // - // fetchTransfers - // - // { - // "timestamp": 1614640878000, - // "asset": "USDT", - // "amount": "25", - // "type": "MAIN_UMFUTURE", - // "status": "CONFIRMED", - // "tranId": 43000126248 - // } - // - const id = this.safeString (transfer, 'tranId'); - const currencyId = this.safeString (transfer, 'asset'); - const code = this.safeCurrencyCode (currencyId, currency); - const amount = this.safeNumber (transfer, 'amount'); - const type = this.safeString (transfer, 'type'); - let fromAccount = undefined; - let toAccount = undefined; - const accountsById = this.safeValue (this.options, 'accountsById', {}); - if (type !== undefined) { - const parts = type.split ('_'); - fromAccount = this.safeValue (parts, 0); - toAccount = this.safeValue (parts, 1); - fromAccount = this.safeString (accountsById, fromAccount, fromAccount); - toAccount = this.safeString (accountsById, toAccount, toAccount); - } - const timestamp = this.safeInteger (transfer, 'timestamp'); - const status = this.parseTransferStatus (this.safeString (transfer, 'status')); - return { - 'info': transfer, - 'id': id, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'currency': code, - 'amount': amount, - 'fromAccount': fromAccount, - 'toAccount': toAccount, - 'status': status, - }; - } - - parseIncome (income, market: Market = undefined) { - // - // { - // "symbol": "ETHUSDT", - // "incomeType": "FUNDING_FEE", - // "income": "0.00134317", - // "asset": "USDT", - // "time": "1621584000000", - // "info": "FUNDING_FEE", - // "tranId": "4480321991774044580", - // "tradeId": "" - // } - // - const marketId = this.safeString (income, 'symbol'); - const symbol = this.safeSymbol (marketId, market, undefined, 'swap'); - const amount = this.safeNumber (income, 'income'); - const currencyId = this.safeString (income, 'asset'); - const code = this.safeCurrencyCode (currencyId); - const id = this.safeString (income, 'tranId'); - const timestamp = this.safeInteger (income, 'time'); - return { - 'info': income, - 'symbol': symbol, - 'code': code, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'id': id, - 'amount': amount, - }; - } - - async transfer (code: string, amount, fromAccount, toAccount, params = {}) { - /** - * @method - * @name binance#transfer - * @description transfer currency internally between wallets on the same account - * @see https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer-user_data - * @see https://binance-docs.github.io/apidocs/spot/en/#isolated-margin-account-transfer-margin - * @param {string} code unified currency code - * @param {float} amount amount to transfer - * @param {string} fromAccount account to transfer from - * @param {string} toAccount account to transfer to - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'asset': currency['id'], - 'amount': this.currencyToPrecision (code, amount), - }; - request['type'] = this.safeString (params, 'type'); - let method = 'sapiPostAssetTransfer'; - if (request['type'] === undefined) { - const symbol = this.safeString (params, 'symbol'); - if (symbol !== undefined) { - params = this.omit (params, 'symbol'); - } - let fromId = this.convertTypeToAccount (fromAccount).toUpperCase (); - let toId = this.convertTypeToAccount (toAccount).toUpperCase (); - if (fromId === 'ISOLATED') { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' transfer () requires params["symbol"] when fromAccount is ' + fromAccount); - } else { - fromId = this.marketId (symbol); - } - } - if (toId === 'ISOLATED') { - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' transfer () requires params["symbol"] when toAccount is ' + toAccount); - } else { - toId = this.marketId (symbol); - } - } - const accountsById = this.safeValue (this.options, 'accountsById', {}); - const fromIsolated = !(fromId in accountsById); - const toIsolated = !(toId in accountsById); - if (fromIsolated || toIsolated) { // Isolated margin transfer - const fromFuture = fromId === 'UMFUTURE' || fromId === 'CMFUTURE'; - const toFuture = toId === 'UMFUTURE' || toId === 'CMFUTURE'; - const fromSpot = fromId === 'MAIN'; - const toSpot = toId === 'MAIN'; - const funding = fromId === 'FUNDING' || toId === 'FUNDING'; - const mining = fromId === 'MINING' || toId === 'MINING'; - const option = fromId === 'OPTION' || toId === 'OPTION'; - const prohibitedWithIsolated = fromFuture || toFuture || mining || funding || option; - if ((fromIsolated || toIsolated) && prohibitedWithIsolated) { - throw new BadRequest (this.id + ' transfer () does not allow transfers between ' + fromAccount + ' and ' + toAccount); - } else if (toSpot && fromIsolated) { - method = 'sapiPostMarginIsolatedTransfer'; - request['transFrom'] = 'ISOLATED_MARGIN'; - request['transTo'] = 'SPOT'; - request['symbol'] = fromId; - } else if (fromSpot && toIsolated) { - method = 'sapiPostMarginIsolatedTransfer'; - request['transFrom'] = 'SPOT'; - request['transTo'] = 'ISOLATED_MARGIN'; - request['symbol'] = toId; - } else { - if (fromIsolated) { - request['fromSymbol'] = fromId; - fromId = 'ISOLATEDMARGIN'; - } - if (toIsolated) { - request['toSymbol'] = toId; - toId = 'ISOLATEDMARGIN'; - } - request['type'] = fromId + '_' + toId; - } - } else { - request['type'] = fromId + '_' + toId; - } - } - params = this.omit (params, 'type'); - const response = await this[method] (this.extend (request, params)); - // - // { - // "tranId":13526853623 - // } - // - return this.parseTransfer (response, currency); - } - - async fetchTransfers (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchTransfers - * @see https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer-user_data - * @description fetch a history of internal transfers made on an account - * @see https://binance-docs.github.io/apidocs/spot/en/#query-user-universal-transfer-history-user_data - * @param {string} code unified currency code of the currency transferred - * @param {int} [since] the earliest time in ms to fetch transfers for - * @param {int} [limit] the maximum number of transfers structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {int} [params.until] the latest time in ms to fetch transfers for - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchTransfers', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchTransfers', code, since, limit, params); - } - let currency = undefined; - if (code !== undefined) { - currency = this.currency (code); - } - const defaultType = this.safeString2 (this.options, 'fetchTransfers', 'defaultType', 'spot'); - const fromAccount = this.safeString (params, 'fromAccount', defaultType); - const defaultTo = (fromAccount === 'future') ? 'spot' : 'future'; - const toAccount = this.safeString (params, 'toAccount', defaultTo); - let type = this.safeString (params, 'type'); - const accountsByType = this.safeValue (this.options, 'accountsByType', {}); - const fromId = this.safeString (accountsByType, fromAccount); - const toId = this.safeString (accountsByType, toAccount); - if (type === undefined) { - if (fromId === undefined) { - const keys = Object.keys (accountsByType); - throw new ExchangeError (this.id + ' fromAccount parameter must be one of ' + keys.join (', ')); - } - if (toId === undefined) { - const keys = Object.keys (accountsByType); - throw new ExchangeError (this.id + ' toAccount parameter must be one of ' + keys.join (', ')); - } - type = fromId + '_' + toId; - } - const request = { - 'type': type, - }; - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['size'] = limit; - } - const until = this.safeInteger (params, 'until'); - if (until !== undefined) { - params = this.omit (params, 'until'); - request['endTime'] = until; - } - const response = await this.sapiGetAssetTransfer (this.extend (request, params)); - // - // { - // "total": 3, - // "rows": [ - // { - // "timestamp": 1614640878000, - // "asset": "USDT", - // "amount": "25", - // "type": "MAIN_UMFUTURE", - // "status": "CONFIRMED", - // "tranId": 43000126248 - // }, - // ] - // } - // - const rows = this.safeValue (response, 'rows', []); - return this.parseTransfers (rows, currency, since, limit); - } - - async fetchDepositAddress (code: string, params = {}) { - /** - * @method - * @name binance#fetchDepositAddress - * @description fetch the deposit address for a currency associated with this account - * @see https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data - * @param {string} code unified currency code - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'coin': currency['id'], - // 'network': 'ETH', // 'BSC', 'XMR', you can get network and isDefault in networkList in the response of sapiGetCapitalConfigDetail - }; - const networks = this.safeValue (this.options, 'networks', {}); - let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH - network = this.safeString (networks, network, network); // handle ERC20>ETH alias - if (network !== undefined) { - request['network'] = network; - params = this.omit (params, 'network'); - } - // has support for the 'network' parameter - // https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data - const response = await this.sapiGetCapitalDepositAddress (this.extend (request, params)); - // - // { - // "currency": "XRP", - // "address": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh", - // "tag": "108618262", - // "info": { - // "coin": "XRP", - // "address": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh", - // "tag": "108618262", - // "url": "https://bithomp.com/explorer/rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh" - // } - // } - // - const address = this.safeString (response, 'address'); - const url = this.safeString (response, 'url'); - let impliedNetwork = undefined; - if (url !== undefined) { - const reverseNetworks = this.safeValue (this.options, 'reverseNetworks', {}); - const parts = url.split ('/'); - let topLevel = this.safeString (parts, 2); - if ((topLevel === 'blockchair.com') || (topLevel === 'viewblock.io')) { - const subLevel = this.safeString (parts, 3); - if (subLevel !== undefined) { - topLevel = topLevel + '/' + subLevel; - } - } - impliedNetwork = this.safeString (reverseNetworks, topLevel); - const impliedNetworks = this.safeValue (this.options, 'impliedNetworks', { - 'ETH': { 'ERC20': 'ETH' }, - 'TRX': { 'TRC20': 'TRX' }, - }); - if (code in impliedNetworks) { - const conversion = this.safeValue (impliedNetworks, code, {}); - impliedNetwork = this.safeString (conversion, impliedNetwork, impliedNetwork); - } - } - let tag = this.safeString (response, 'tag', ''); - if (tag.length === 0) { - tag = undefined; - } - this.checkAddress (address); - return { - 'currency': code, - 'address': address, - 'tag': tag, - 'network': impliedNetwork, - 'info': response, - }; - } - - async fetchTransactionFees (codes = undefined, params = {}) { - /** - * @method - * @name binance#fetchTransactionFees - * @deprecated - * @description please use fetchDepositWithdrawFees instead - * @see https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data - * @param {string[]|undefined} codes not used by binance fetchTransactionFees () - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} - */ - await this.loadMarkets (); - const response = await this.sapiGetCapitalConfigGetall (params); - // - // [ - // { - // "coin": "BAT", - // "depositAllEnable": true, - // "withdrawAllEnable": true, - // "name": "Basic Attention Token", - // "free": "0", - // "locked": "0", - // "freeze": "0", - // "withdrawing": "0", - // "ipoing": "0", - // "ipoable": "0", - // "storage": "0", - // "isLegalMoney": false, - // "trading": true, - // "networkList": [ - // { - // "network": "BNB", - // "coin": "BAT", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": false, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": '', - // "withdrawDesc": '', - // "specialTips": "The name of this asset is Basic Attention Token (BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.", - // "name": "BEP2", - // "resetAddressStatus": false, - // "addressRegex": "^(bnb1)[0-9a-z]{38}$", - // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", - // "withdrawFee": "0.27", - // "withdrawMin": "0.54", - // "withdrawMax": "10000000000", - // "minConfirm": "1", - // "unLockConfirm": "0" - // }, - // { - // "network": "BSC", - // "coin": "BAT", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": false, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": '', - // "withdrawDesc": '', - // "specialTips": "The name of this asset is Basic Attention Token. Please ensure you are depositing Basic Attention Token (BAT) tokens under the contract address ending in 9766e.", - // "name": "BEP20 (BSC)", - // "resetAddressStatus": false, - // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", - // "memoRegex": '', - // "withdrawFee": "0.27", - // "withdrawMin": "0.54", - // "withdrawMax": "10000000000", - // "minConfirm": "15", - // "unLockConfirm": "0" - // }, - // { - // "network": "ETH", - // "coin": "BAT", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": true, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": '', - // "withdrawDesc": '', - // "specialTips": "The name of this asset is Basic Attention Token. Please ensure you are depositing Basic Attention Token (BAT) tokens under the contract address ending in 887ef.", - // "name": "ERC20", - // "resetAddressStatus": false, - // "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", - // "memoRegex": '', - // "withdrawFee": "27", - // "withdrawMin": "54", - // "withdrawMax": "10000000000", - // "minConfirm": "12", - // "unLockConfirm": "0" - // } - // ] - // } - // ] - // - const withdrawFees = {}; - for (let i = 0; i < response.length; i++) { - const entry = response[i]; - const currencyId = this.safeString (entry, 'coin'); - const code = this.safeCurrencyCode (currencyId); - const networkList = this.safeValue (entry, 'networkList', []); - withdrawFees[code] = {}; - for (let j = 0; j < networkList.length; j++) { - const networkEntry = networkList[j]; - const networkId = this.safeString (networkEntry, 'network'); - const networkCode = this.safeCurrencyCode (networkId); - const fee = this.safeNumber (networkEntry, 'withdrawFee'); - withdrawFees[code][networkCode] = fee; - } - } - return { - 'withdraw': withdrawFees, - 'deposit': {}, - 'info': response, - }; - } - - async fetchDepositWithdrawFees (codes: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchDepositWithdrawFees - * @description fetch deposit and withdraw fees - * @see https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data - * @param {string[]|undefined} codes not used by binance fetchDepositWithdrawFees () - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} - */ - await this.loadMarkets (); - const response = await this.sapiGetCapitalConfigGetall (params); - // - // [ - // { - // "coin": "BAT", - // "depositAllEnable": true, - // "withdrawAllEnable": true, - // "name": "Basic Attention Token", - // "free": "0", - // "locked": "0", - // "freeze": "0", - // "withdrawing": "0", - // "ipoing": "0", - // "ipoable": "0", - // "storage": "0", - // "isLegalMoney": false, - // "trading": true, - // "networkList": [ - // { - // "network": "BNB", - // "coin": "BAT", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": false, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": '', - // "withdrawDesc": '', - // "specialTips": "The name of this asset is Basic Attention Token (BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.", - // "name": "BEP2", - // "resetAddressStatus": false, - // "addressRegex": "^(bnb1)[0-9a-z]{38}$", - // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", - // "withdrawFee": "0.27", - // "withdrawMin": "0.54", - // "withdrawMax": "10000000000", - // "minConfirm": "1", - // "unLockConfirm": "0" - // }, - // ... - // ] - // } - // ] - // - return this.parseDepositWithdrawFees (response, codes, 'coin'); - } - - parseDepositWithdrawFee (fee, currency: Currency = undefined) { - // - // { - // "coin": "BAT", - // "depositAllEnable": true, - // "withdrawAllEnable": true, - // "name": "Basic Attention Token", - // "free": "0", - // "locked": "0", - // "freeze": "0", - // "withdrawing": "0", - // "ipoing": "0", - // "ipoable": "0", - // "storage": "0", - // "isLegalMoney": false, - // "trading": true, - // "networkList": [ - // { - // "network": "BNB", - // "coin": "BAT", - // "withdrawIntegerMultiple": "0.00000001", - // "isDefault": false, - // "depositEnable": true, - // "withdrawEnable": true, - // "depositDesc": '', - // "withdrawDesc": '', - // "specialTips": "The name of this asset is Basic Attention Token (BAT). Both a MEMO and an Address are required to successfully deposit your BEP2 tokens to Binance.", - // "name": "BEP2", - // "resetAddressStatus": false, - // "addressRegex": "^(bnb1)[0-9a-z]{38}$", - // "memoRegex": "^[0-9A-Za-z\\-_]{1,120}$", - // "withdrawFee": "0.27", - // "withdrawMin": "0.54", - // "withdrawMax": "10000000000", - // "minConfirm": "1", - // "unLockConfirm": "0" - // }, - // ... - // ] - // } - // - const networkList = this.safeValue (fee, 'networkList', []); - const result = this.depositWithdrawFee (fee); - for (let j = 0; j < networkList.length; j++) { - const networkEntry = networkList[j]; - const networkId = this.safeString (networkEntry, 'network'); - const networkCode = this.networkIdToCode (networkId); - const withdrawFee = this.safeNumber (networkEntry, 'withdrawFee'); - const isDefault = this.safeValue (networkEntry, 'isDefault'); - if (isDefault === true) { - result['withdraw'] = { - 'fee': withdrawFee, - 'percentage': undefined, - }; - } - result['networks'][networkCode] = { - 'withdraw': { - 'fee': withdrawFee, - 'percentage': undefined, - }, - 'deposit': { - 'fee': undefined, - 'percentage': undefined, - }, - }; - } - return result; - } - - async withdraw (code: string, amount, address, tag = undefined, params = {}) { - /** - * @method - * @name binance#withdraw - * @description make a withdrawal - * @see https://binance-docs.github.io/apidocs/spot/en/#withdraw-user_data - * @param {string} code unified currency code - * @param {float} amount the amount to withdraw - * @param {string} address the address to withdraw to - * @param {string} tag - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure} - */ - [ tag, params ] = this.handleWithdrawTagAndParams (tag, params); - this.checkAddress (address); - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'coin': currency['id'], - 'address': address, - 'amount': amount, - // https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi - // issue sapiGetCapitalConfigGetall () to get networks for withdrawing USDT ERC20 vs USDT Omni - // 'network': 'ETH', // 'BTC', 'TRX', etc, optional - }; - if (tag !== undefined) { - request['addressTag'] = tag; - } - const networks = this.safeValue (this.options, 'networks', {}); - let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH - network = this.safeString (networks, network, network); // handle ERC20>ETH alias - if (network !== undefined) { - request['network'] = network; - params = this.omit (params, 'network'); - } - const response = await this.sapiPostCapitalWithdrawApply (this.extend (request, params)); - // { id: '9a67628b16ba4988ae20d329333f16bc' } - return this.parseTransaction (response, currency); - } - - parseTradingFee (fee, market: Market = undefined) { - // - // spot - // [ - // { - // "symbol": "BTCUSDT", - // "makerCommission": "0.001", - // "takerCommission": "0.001" - // } - // ] - // - // swap - // { - // "symbol": "BTCUSD_PERP", - // "makerCommissionRate": "0.00015", // 0.015% - // "takerCommissionRate": "0.00040" // 0.040% - // } - // - const marketId = this.safeString (fee, 'symbol'); - const symbol = this.safeSymbol (marketId, market, undefined, 'spot'); - return { - 'info': fee, - 'symbol': symbol, - 'maker': this.safeNumber2 (fee, 'makerCommission', 'makerCommissionRate'), - 'taker': this.safeNumber2 (fee, 'takerCommission', 'takerCommissionRate'), - }; - } - - async fetchTradingFee (symbol: string, params = {}) { - /** - * @method - * @name binance#fetchTradingFee - * @description fetch the trading fees for a market - * @see https://binance-docs.github.io/apidocs/spot/en/#trade-fee-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#user-commission-rate-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#user-commission-rate-user_data - * @param {string} symbol unified market symbol - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - const defaultType = this.safeString2 (this.options, 'fetchTradingFee', 'defaultType', 'linear'); - const type = this.safeString (params, 'type', defaultType); - params = this.omit (params, 'type'); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchTradingFee', market, params); - const isSpotOrMargin = (type === 'spot') || (type === 'margin'); - const isLinear = this.isLinear (type, subType); - const isInverse = this.isInverse (type, subType); - const request = { - 'symbol': market['id'], - }; - let response = undefined; - if (isSpotOrMargin) { - response = await this.sapiGetAssetTradeFee (this.extend (request, params)); - } else if (isLinear) { - response = await this.fapiPrivateGetCommissionRate (this.extend (request, params)); - } else if (isInverse) { - response = await this.dapiPrivateGetCommissionRate (this.extend (request, params)); - } - // - // spot - // [ - // { - // "symbol": "BTCUSDT", - // "makerCommission": "0.001", - // "takerCommission": "0.001" - // } - // ] - // - // swap - // { - // "symbol": "BTCUSD_PERP", - // "makerCommissionRate": "0.00015", // 0.015% - // "takerCommissionRate": "0.00040" // 0.040% - // } - // - let data = response; - if (Array.isArray (data)) { - data = this.safeValue (data, 0, {}); - } - return this.parseTradingFee (data); - } - - async fetchTradingFees (params = {}) { - /** - * @method - * @name binance#fetchTradingFees - * @description fetch the trading fees for multiple markets - * @see https://binance-docs.github.io/apidocs/spot/en/#trade-fee-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols - */ - await this.loadMarkets (); - let method = undefined; - let type = undefined; - [ type, params ] = this.handleMarketTypeAndParams ('fetchTradingFees', undefined, params); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchTradingFees', undefined, params, 'linear'); - const isSpotOrMargin = (type === 'spot') || (type === 'margin'); - const isLinear = this.isLinear (type, subType); - const isInverse = this.isInverse (type, subType); - if (isSpotOrMargin) { - method = 'sapiGetAssetTradeFee'; - } else if (isLinear) { - method = 'fapiPrivateV2GetAccount'; - } else if (isInverse) { - method = 'dapiPrivateGetAccount'; - } - const response = await this[method] (params); - // - // sapi / spot - // - // [ - // { - // "symbol": "ZRXBNB", - // "makerCommission": "0.001", - // "takerCommission": "0.001" - // }, - // { - // "symbol": "ZRXBTC", - // "makerCommission": "0.001", - // "takerCommission": "0.001" - // }, - // ] - // - // fapi / future / linear - // - // { - // "feeTier": 0, // account commisssion tier - // "canTrade": true, // if can trade - // "canDeposit": true, // if can transfer in asset - // "canWithdraw": true, // if can transfer out asset - // "updateTime": 0, - // "totalInitialMargin": "0.00000000", // total initial margin required with current mark price (useless with isolated positions), only for USDT asset - // "totalMaintMargin": "0.00000000", // total maintenance margin required, only for USDT asset - // "totalWalletBalance": "23.72469206", // total wallet balance, only for USDT asset - // "totalUnrealizedProfit": "0.00000000", // total unrealized profit, only for USDT asset - // "totalMarginBalance": "23.72469206", // total margin balance, only for USDT asset - // "totalPositionInitialMargin": "0.00000000", // initial margin required for positions with current mark price, only for USDT asset - // "totalOpenOrderInitialMargin": "0.00000000", // initial margin required for open orders with current mark price, only for USDT asset - // "totalCrossWalletBalance": "23.72469206", // crossed wallet balance, only for USDT asset - // "totalCrossUnPnl": "0.00000000", // unrealized profit of crossed positions, only for USDT asset - // "availableBalance": "23.72469206", // available balance, only for USDT asset - // "maxWithdrawAmount": "23.72469206" // maximum amount for transfer out, only for USDT asset - // ... - // } - // - // dapi / delivery / inverse - // - // { - // "canDeposit": true, - // "canTrade": true, - // "canWithdraw": true, - // "feeTier": 2, - // "updateTime": 0 - // } - // - if (isSpotOrMargin) { - // - // [ - // { - // "symbol": "ZRXBNB", - // "makerCommission": "0.001", - // "takerCommission": "0.001" - // }, - // { - // "symbol": "ZRXBTC", - // "makerCommission": "0.001", - // "takerCommission": "0.001" - // }, - // ] - // - const result = {}; - for (let i = 0; i < response.length; i++) { - const fee = this.parseTradingFee (response[i]); - const symbol = fee['symbol']; - result[symbol] = fee; - } - return result; - } else if (isLinear) { - // - // { - // "feeTier": 0, // account commisssion tier - // "canTrade": true, // if can trade - // "canDeposit": true, // if can transfer in asset - // "canWithdraw": true, // if can transfer out asset - // "updateTime": 0, - // "totalInitialMargin": "0.00000000", // total initial margin required with current mark price (useless with isolated positions), only for USDT asset - // "totalMaintMargin": "0.00000000", // total maintenance margin required, only for USDT asset - // "totalWalletBalance": "23.72469206", // total wallet balance, only for USDT asset - // "totalUnrealizedProfit": "0.00000000", // total unrealized profit, only for USDT asset - // "totalMarginBalance": "23.72469206", // total margin balance, only for USDT asset - // "totalPositionInitialMargin": "0.00000000", // initial margin required for positions with current mark price, only for USDT asset - // "totalOpenOrderInitialMargin": "0.00000000", // initial margin required for open orders with current mark price, only for USDT asset - // "totalCrossWalletBalance": "23.72469206", // crossed wallet balance, only for USDT asset - // "totalCrossUnPnl": "0.00000000", // unrealized profit of crossed positions, only for USDT asset - // "availableBalance": "23.72469206", // available balance, only for USDT asset - // "maxWithdrawAmount": "23.72469206" // maximum amount for transfer out, only for USDT asset - // ... - // } - // - const symbols = Object.keys (this.markets); - const result = {}; - const feeTier = this.safeInteger (response, 'feeTier'); - const feeTiers = this.fees['linear']['trading']['tiers']; - const maker = feeTiers['maker'][feeTier][1]; - const taker = feeTiers['taker'][feeTier][1]; - for (let i = 0; i < symbols.length; i++) { - const symbol = symbols[i]; - const market = this.markets[symbol]; - if (market['linear']) { - result[symbol] = { - 'info': { - 'feeTier': feeTier, - }, - 'symbol': symbol, - 'maker': maker, - 'taker': taker, - }; - } - } - return result; - } else if (isInverse) { - // - // { - // "canDeposit": true, - // "canTrade": true, - // "canWithdraw": true, - // "feeTier": 2, - // "updateTime": 0 - // } - // - const symbols = Object.keys (this.markets); - const result = {}; - const feeTier = this.safeInteger (response, 'feeTier'); - const feeTiers = this.fees['inverse']['trading']['tiers']; - const maker = feeTiers['maker'][feeTier][1]; - const taker = feeTiers['taker'][feeTier][1]; - for (let i = 0; i < symbols.length; i++) { - const symbol = symbols[i]; - const market = this.markets[symbol]; - if (market['inverse']) { - result[symbol] = { - 'info': { - 'feeTier': feeTier, - }, - 'symbol': symbol, - 'maker': maker, - 'taker': taker, - }; - } - } - return result; - } - return undefined; - } - - async futuresTransfer (code: string, amount, type, params = {}) { - /** - * @method - * @name binance#futuresTransfer - * @ignore - * @description transfer between futures account - * @see https://binance-docs.github.io/apidocs/spot/en/#new-future-account-transfer-user_data - * @param {string} code unified currency code - * @param {float} amount the amount to transfer - * @param {string} type 1 - transfer from spot account to USDT-Ⓜ futures account, 2 - transfer from USDT-Ⓜ futures account to spot account, 3 - transfer from spot account to COIN-Ⓜ futures account, 4 - transfer from COIN-Ⓜ futures account to spot account - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {float} params.recvWindow - * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=futures-transfer-structure} - */ - if ((type < 1) || (type > 4)) { - throw new ArgumentsRequired (this.id + ' type must be between 1 and 4'); - } - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'asset': currency['id'], - 'amount': amount, - 'type': type, - }; - const response = await this.sapiPostFuturesTransfer (this.extend (request, params)); - // - // { - // "tranId": 100000001 - // } - // - return this.parseTransfer (response, currency); - } - - async fetchFundingRate (symbol: string, params = {}) { - /** - * @method - * @name binance#fetchFundingRate - * @description fetch the current funding rate - * @see https://binance-docs.github.io/apidocs/futures/en/#mark-price - * @see https://binance-docs.github.io/apidocs/delivery/en/#index-price-and-mark-price - * @param {string} symbol unified market symbol - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - let method = undefined; - if (market['linear']) { - method = 'fapiPublicGetPremiumIndex'; - } else if (market['inverse']) { - method = 'dapiPublicGetPremiumIndex'; - } else { - throw new NotSupported (this.id + ' fetchFundingRate() supports linear and inverse contracts only'); - } - let response = await this[method] (this.extend (request, params)); - if (market['inverse']) { - response = response[0]; - } - // - // { - // "symbol": "BTCUSDT", - // "markPrice": "45802.81129892", - // "indexPrice": "45745.47701915", - // "estimatedSettlePrice": "45133.91753671", - // "lastFundingRate": "0.00063521", - // "interestRate": "0.00010000", - // "nextFundingTime": "1621267200000", - // "time": "1621252344001" - // } - // - return this.parseFundingRate (response, market); - } - - async fetchFundingRateHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchFundingRateHistory - * @description fetches historical funding rate prices - * @see https://binance-docs.github.io/apidocs/futures/en/#get-funding-rate-history - * @see https://binance-docs.github.io/apidocs/delivery/en/#get-funding-rate-history-of-perpetual-futures - * @param {string} symbol unified symbol of the market to fetch the funding rate history for - * @param {int} [since] timestamp in ms of the earliest funding rate to fetch - * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {int} [params.until] timestamp in ms of the latest funding rate - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} - */ - await this.loadMarkets (); - const request = {}; - let method = undefined; - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchFundingRateHistory', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDeterministic ('fetchFundingRateHistory', symbol, since, limit, '8h', params) as FundingRateHistory[]; - } - const defaultType = this.safeString2 (this.options, 'fetchFundingRateHistory', 'defaultType', 'future'); - const type = this.safeString (params, 'type', defaultType); - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - symbol = market['symbol']; - request['symbol'] = market['id']; - } - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchFundingRateHistory', market, params, 'linear'); - params = this.omit (params, 'type'); - if (this.isLinear (type, subType)) { - method = 'fapiPublicGetFundingRate'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPublicGetFundingRate'; - } - if (method === undefined) { - throw new NotSupported (this.id + ' fetchFundingRateHistory() is not supported for ' + type + ' markets'); - } - if (since !== undefined) { - request['startTime'] = since; - } - const until = this.safeInteger2 (params, 'until', 'till'); // unified in milliseconds - const endTime = this.safeInteger (params, 'endTime', until); // exchange-specific in milliseconds - params = this.omit (params, [ 'endTime', 'till', 'until' ]); - if (endTime !== undefined) { - request['endTime'] = endTime; - } - if (limit !== undefined) { - request['limit'] = limit; - } - const response = await this[method] (this.extend (request, params)); - // - // { - // "symbol": "BTCUSDT", - // "fundingRate": "0.00063521", - // "fundingTime": "1621267200000", - // } - // - const rates = []; - for (let i = 0; i < response.length; i++) { - const entry = response[i]; - const timestamp = this.safeInteger (entry, 'fundingTime'); - rates.push ({ - 'info': entry, - 'symbol': this.safeSymbol (this.safeString (entry, 'symbol'), undefined, undefined, 'swap'), - 'fundingRate': this.safeNumber (entry, 'fundingRate'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - }); - } - const sorted = this.sortBy (rates, 'timestamp'); - return this.filterBySymbolSinceLimit (sorted, symbol, since, limit) as FundingRateHistory[]; - } - - async fetchFundingRates (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchFundingRates - * @description fetch the funding rate for multiple markets - * @see https://binance-docs.github.io/apidocs/futures/en/#mark-price - * @see https://binance-docs.github.io/apidocs/delivery/en/#index-price-and-mark-price - * @param {string[]|undefined} symbols list of unified market symbols - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a dictionary of [funding rates structures]{@link https://docs.ccxt.com/#/?id=funding-rates-structure}, indexe by market symbols - */ - await this.loadMarkets (); - symbols = this.marketSymbols (symbols); - let method = undefined; - const defaultType = this.safeString2 (this.options, 'fetchFundingRates', 'defaultType', 'future'); - const type = this.safeString (params, 'type', defaultType); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchFundingRates', undefined, params, 'linear'); - const query = this.omit (params, 'type'); - if (this.isLinear (type, subType)) { - method = 'fapiPublicGetPremiumIndex'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPublicGetPremiumIndex'; - } else { - throw new NotSupported (this.id + ' fetchFundingRates() supports linear and inverse contracts only'); - } - const response = await this[method] (query); - const result = []; - for (let i = 0; i < response.length; i++) { - const entry = response[i]; - const parsed = this.parseFundingRate (entry); - result.push (parsed); - } - return this.filterByArray (result, 'symbol', symbols); - } - - parseFundingRate (contract, market: Market = undefined) { - // ensure it matches with https://www.binance.com/en/futures/funding-history/0 - // - // { - // "symbol": "BTCUSDT", - // "markPrice": "45802.81129892", - // "indexPrice": "45745.47701915", - // "estimatedSettlePrice": "45133.91753671", - // "lastFundingRate": "0.00063521", - // "interestRate": "0.00010000", - // "nextFundingTime": "1621267200000", - // "time": "1621252344001" - // } - // - const timestamp = this.safeInteger (contract, 'time'); - const marketId = this.safeString (contract, 'symbol'); - const symbol = this.safeSymbol (marketId, market, undefined, 'contract'); - const markPrice = this.safeNumber (contract, 'markPrice'); - const indexPrice = this.safeNumber (contract, 'indexPrice'); - const interestRate = this.safeNumber (contract, 'interestRate'); - const estimatedSettlePrice = this.safeNumber (contract, 'estimatedSettlePrice'); - const fundingRate = this.safeNumber (contract, 'lastFundingRate'); - const fundingTime = this.safeInteger (contract, 'nextFundingTime'); - return { - 'info': contract, - 'symbol': symbol, - 'markPrice': markPrice, - 'indexPrice': indexPrice, - 'interestRate': interestRate, - 'estimatedSettlePrice': estimatedSettlePrice, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'fundingRate': fundingRate, - 'fundingTimestamp': fundingTime, - 'fundingDatetime': this.iso8601 (fundingTime), - 'nextFundingRate': undefined, - 'nextFundingTimestamp': undefined, - 'nextFundingDatetime': undefined, - 'previousFundingRate': undefined, - 'previousFundingTimestamp': undefined, - 'previousFundingDatetime': undefined, - }; - } - - parseAccountPositions (account) { - const positions = this.safeValue (account, 'positions'); - const assets = this.safeValue (account, 'assets', []); - const balances = {}; - for (let i = 0; i < assets.length; i++) { - const entry = assets[i]; - const currencyId = this.safeString (entry, 'asset'); - const code = this.safeCurrencyCode (currencyId); - const crossWalletBalance = this.safeString (entry, 'crossWalletBalance'); - const crossUnPnl = this.safeString (entry, 'crossUnPnl'); - balances[code] = { - 'crossMargin': Precise.stringAdd (crossWalletBalance, crossUnPnl), - 'crossWalletBalance': crossWalletBalance, - }; - } - const result = []; - for (let i = 0; i < positions.length; i++) { - const position = positions[i]; - const marketId = this.safeString (position, 'symbol'); - const market = this.safeMarket (marketId, undefined, undefined, 'contract'); - const code = market['linear'] ? market['quote'] : market['base']; - // sometimes not all the codes are correctly returned... - if (code in balances) { - const parsed = this.parseAccountPosition (this.extend (position, { - 'crossMargin': balances[code]['crossMargin'], - 'crossWalletBalance': balances[code]['crossWalletBalance'], - }), market); - result.push (parsed); - } - } - return result; - } - - parseAccountPosition (position, market: Market = undefined) { - // - // usdm - // { - // "symbol": "BTCBUSD", - // "initialMargin": "0", - // "maintMargin": "0", - // "unrealizedProfit": "0.00000000", - // "positionInitialMargin": "0", - // "openOrderInitialMargin": "0", - // "leverage": "20", - // "isolated": false, - // "entryPrice": "0.0000", - // "maxNotional": "100000", - // "positionSide": "BOTH", - // "positionAmt": "0.000", - // "notional": "0", - // "isolatedWallet": "0", - // "updateTime": "0", - // "crossMargin": "100.93634809", - // } - // - // coinm - // { - // "symbol": "BTCUSD_210625", - // "initialMargin": "0.00024393", - // "maintMargin": "0.00002439", - // "unrealizedProfit": "-0.00000163", - // "positionInitialMargin": "0.00024393", - // "openOrderInitialMargin": "0", - // "leverage": "10", - // "isolated": false, - // "positionSide": "BOTH", - // "entryPrice": "41021.20000069", - // "maxQty": "100", - // "notionalValue": "0.00243939", - // "isolatedWallet": "0", - // "crossMargin": "0.314" - // "crossWalletBalance": "34", - // } - // - const marketId = this.safeString (position, 'symbol'); - market = this.safeMarket (marketId, market, undefined, 'contract'); - const symbol = this.safeString (market, 'symbol'); - const leverageString = this.safeString (position, 'leverage'); - const leverage = parseInt (leverageString); - const initialMarginString = this.safeString (position, 'initialMargin'); - const initialMargin = this.parseNumber (initialMarginString); - let initialMarginPercentageString = Precise.stringDiv ('1', leverageString, 8); - const rational = this.isRoundNumber (1000 % leverage); - if (!rational) { - initialMarginPercentageString = Precise.stringDiv (Precise.stringAdd (initialMarginPercentageString, '1e-8'), '1', 8); - } - // as oppose to notionalValue - const usdm = ('notional' in position); - const maintenanceMarginString = this.safeString (position, 'maintMargin'); - const maintenanceMargin = this.parseNumber (maintenanceMarginString); - const entryPriceString = this.safeString (position, 'entryPrice'); - let entryPrice = this.parseNumber (entryPriceString); - const notionalString = this.safeString2 (position, 'notional', 'notionalValue'); - const notionalStringAbs = Precise.stringAbs (notionalString); - const notional = this.parseNumber (notionalStringAbs); - let contractsString = this.safeString (position, 'positionAmt'); - let contractsStringAbs = Precise.stringAbs (contractsString); - if (contractsString === undefined) { - const entryNotional = Precise.stringMul (Precise.stringMul (leverageString, initialMarginString), entryPriceString); - const contractSizeNew = this.safeString (market, 'contractSize'); - contractsString = Precise.stringDiv (entryNotional, contractSizeNew); - contractsStringAbs = Precise.stringDiv (Precise.stringAdd (contractsString, '0.5'), '1', 0); - } - const contracts = this.parseNumber (contractsStringAbs); - const leverageBrackets = this.safeValue (this.options, 'leverageBrackets', {}); - const leverageBracket = this.safeValue (leverageBrackets, symbol, []); - let maintenanceMarginPercentageString = undefined; - for (let i = 0; i < leverageBracket.length; i++) { - const bracket = leverageBracket[i]; - if (Precise.stringLt (notionalStringAbs, bracket[0])) { - break; - } - maintenanceMarginPercentageString = bracket[1]; - } - const maintenanceMarginPercentage = this.parseNumber (maintenanceMarginPercentageString); - const unrealizedPnlString = this.safeString (position, 'unrealizedProfit'); - const unrealizedPnl = this.parseNumber (unrealizedPnlString); - let timestamp = this.safeInteger (position, 'updateTime'); - if (timestamp === 0) { - timestamp = undefined; - } - const isolated = this.safeValue (position, 'isolated'); - let marginMode = undefined; - let collateralString = undefined; - let walletBalance = undefined; - if (isolated) { - marginMode = 'isolated'; - walletBalance = this.safeString (position, 'isolatedWallet'); - collateralString = Precise.stringAdd (walletBalance, unrealizedPnlString); - } else { - marginMode = 'cross'; - walletBalance = this.safeString (position, 'crossWalletBalance'); - collateralString = this.safeString (position, 'crossMargin'); - } - const collateral = this.parseNumber (collateralString); - let marginRatio = undefined; - let side = undefined; - let percentage = undefined; - let liquidationPriceStringRaw = undefined; - let liquidationPrice = undefined; - const contractSize = this.safeValue (market, 'contractSize'); - const contractSizeString = this.numberToString (contractSize); - if (Precise.stringEquals (notionalString, '0')) { - entryPrice = undefined; - } else { - side = Precise.stringLt (notionalString, '0') ? 'short' : 'long'; - marginRatio = this.parseNumber (Precise.stringDiv (Precise.stringAdd (Precise.stringDiv (maintenanceMarginString, collateralString), '5e-5'), '1', 4)); - percentage = this.parseNumber (Precise.stringMul (Precise.stringDiv (unrealizedPnlString, initialMarginString, 4), '100')); - if (usdm) { - // calculate liquidation price - // - // liquidationPrice = (walletBalance / (contracts * (±1 + mmp))) + (±entryPrice / (±1 + mmp)) - // - // mmp = maintenanceMarginPercentage - // where ± is negative for long and positive for short - // TODO: calculate liquidation price for coinm contracts - let onePlusMaintenanceMarginPercentageString = undefined; - let entryPriceSignString = entryPriceString; - if (side === 'short') { - onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('1', maintenanceMarginPercentageString); - } else { - onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('-1', maintenanceMarginPercentageString); - entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); - } - const leftSide = Precise.stringDiv (walletBalance, Precise.stringMul (contractsStringAbs, onePlusMaintenanceMarginPercentageString)); - const rightSide = Precise.stringDiv (entryPriceSignString, onePlusMaintenanceMarginPercentageString); - liquidationPriceStringRaw = Precise.stringAdd (leftSide, rightSide); - } else { - // calculate liquidation price - // - // liquidationPrice = (contracts * contractSize(±1 - mmp)) / (±1/entryPrice * contracts * contractSize - walletBalance) - // - let onePlusMaintenanceMarginPercentageString = undefined; - let entryPriceSignString = entryPriceString; - if (side === 'short') { - onePlusMaintenanceMarginPercentageString = Precise.stringSub ('1', maintenanceMarginPercentageString); - } else { - onePlusMaintenanceMarginPercentageString = Precise.stringSub ('-1', maintenanceMarginPercentageString); - entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); - } - const size = Precise.stringMul (contractsStringAbs, contractSizeString); - const leftSide = Precise.stringMul (size, onePlusMaintenanceMarginPercentageString); - const rightSide = Precise.stringSub (Precise.stringMul (Precise.stringDiv ('1', entryPriceSignString), size), walletBalance); - liquidationPriceStringRaw = Precise.stringDiv (leftSide, rightSide); - } - const pricePrecision = market['precision']['price']; - const pricePrecisionPlusOne = pricePrecision + 1; - const pricePrecisionPlusOneString = pricePrecisionPlusOne.toString (); - // round half up - const rounder = new Precise ('5e-' + pricePrecisionPlusOneString); - const rounderString = rounder.toString (); - const liquidationPriceRoundedString = Precise.stringAdd (rounderString, liquidationPriceStringRaw); - let truncatedLiquidationPrice = Precise.stringDiv (liquidationPriceRoundedString, '1', pricePrecision); - if (truncatedLiquidationPrice[0] === '-') { - // user cannot be liquidated - // since he has more collateral than the size of the position - truncatedLiquidationPrice = undefined; - } - liquidationPrice = this.parseNumber (truncatedLiquidationPrice); - } - const positionSide = this.safeString (position, 'positionSide'); - const hedged = positionSide !== 'BOTH'; - return { - 'info': position, - 'id': undefined, - 'symbol': symbol, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'initialMargin': initialMargin, - 'initialMarginPercentage': this.parseNumber (initialMarginPercentageString), - 'maintenanceMargin': maintenanceMargin, - 'maintenanceMarginPercentage': maintenanceMarginPercentage, - 'entryPrice': entryPrice, - 'notional': notional, - 'leverage': this.parseNumber (leverageString), - 'unrealizedPnl': unrealizedPnl, - 'contracts': contracts, - 'contractSize': contractSize, - 'marginRatio': marginRatio, - 'liquidationPrice': liquidationPrice, - 'markPrice': undefined, - 'collateral': collateral, - 'marginMode': marginMode, - 'side': side, - 'hedged': hedged, - 'percentage': percentage, - }; - } - - parsePositionRisk (position, market: Market = undefined) { - // - // usdm - // - // { - // "symbol": "BTCUSDT", - // "positionAmt": "0.001", - // "entryPrice": "43578.07000", - // "markPrice": "43532.30000000", - // "unRealizedProfit": "-0.04577000", - // "liquidationPrice": "21841.24993976", - // "leverage": "2", - // "maxNotionalValue": "300000000", - // "marginType": "isolated", - // "isolatedMargin": "21.77841506", - // "isAutoAddMargin": "false", - // "positionSide": "BOTH", - // "notional": "43.53230000", - // "isolatedWallet": "21.82418506", - // "updateTime": "1621358023886" - // } - // - // coinm - // - // { - // "symbol": "BTCUSD_PERP", - // "positionAmt": "2", - // "entryPrice": "37643.10000021", - // "markPrice": "38103.05510455", - // "unRealizedProfit": "0.00006413", - // "liquidationPrice": "25119.97445760", - // "leverage": "2", - // "maxQty": "1500", - // "marginType": "isolated", - // "isolatedMargin": "0.00274471", - // "isAutoAddMargin": "false", - // "positionSide": "BOTH", - // "notionalValue": "0.00524892", - // "isolatedWallet": "0.00268058" - // } - // - const marketId = this.safeString (position, 'symbol'); - market = this.safeMarket (marketId, market, undefined, 'contract'); - const symbol = this.safeString (market, 'symbol'); - const leverageBrackets = this.safeValue (this.options, 'leverageBrackets', {}); - const leverageBracket = this.safeValue (leverageBrackets, symbol, []); - const notionalString = this.safeString2 (position, 'notional', 'notionalValue'); - const notionalStringAbs = Precise.stringAbs (notionalString); - let maintenanceMarginPercentageString = undefined; - for (let i = 0; i < leverageBracket.length; i++) { - const bracket = leverageBracket[i]; - if (Precise.stringLt (notionalStringAbs, bracket[0])) { - break; - } - maintenanceMarginPercentageString = bracket[1]; - } - const notional = this.parseNumber (notionalStringAbs); - const contractsAbs = Precise.stringAbs (this.safeString (position, 'positionAmt')); - const contracts = this.parseNumber (contractsAbs); - const unrealizedPnlString = this.safeString (position, 'unRealizedProfit'); - const unrealizedPnl = this.parseNumber (unrealizedPnlString); - const leverageString = this.safeString (position, 'leverage'); - const leverage = parseInt (leverageString); - const liquidationPriceString = this.omitZero (this.safeString (position, 'liquidationPrice')); - const liquidationPrice = this.parseNumber (liquidationPriceString); - let collateralString = undefined; - const marginMode = this.safeString (position, 'marginType'); - let side = undefined; - if (Precise.stringGt (notionalString, '0')) { - side = 'long'; - } else if (Precise.stringLt (notionalString, '0')) { - side = 'short'; - } - const entryPriceString = this.safeString (position, 'entryPrice'); - const entryPrice = this.parseNumber (entryPriceString); - const contractSize = this.safeValue (market, 'contractSize'); - const contractSizeString = this.numberToString (contractSize); - // as oppose to notionalValue - const linear = ('notional' in position); - if (marginMode === 'cross') { - // calculate collateral - const precision = this.safeValue (market, 'precision', {}); - if (linear) { - // walletBalance = (liquidationPrice * (±1 + mmp) ± entryPrice) * contracts - let onePlusMaintenanceMarginPercentageString = undefined; - let entryPriceSignString = entryPriceString; - if (side === 'short') { - onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('1', maintenanceMarginPercentageString); - entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); - } else { - onePlusMaintenanceMarginPercentageString = Precise.stringAdd ('-1', maintenanceMarginPercentageString); - } - const inner = Precise.stringMul (liquidationPriceString, onePlusMaintenanceMarginPercentageString); - const leftSide = Precise.stringAdd (inner, entryPriceSignString); - const pricePrecision = this.safeInteger (precision, 'price'); - const quotePrecision = this.safeInteger (precision, 'quote', pricePrecision); - if (quotePrecision !== undefined) { - collateralString = Precise.stringDiv (Precise.stringMul (leftSide, contractsAbs), '1', quotePrecision); - } - } else { - // walletBalance = (contracts * contractSize) * (±1/entryPrice - (±1 - mmp) / liquidationPrice) - let onePlusMaintenanceMarginPercentageString = undefined; - let entryPriceSignString = entryPriceString; - if (side === 'short') { - onePlusMaintenanceMarginPercentageString = Precise.stringSub ('1', maintenanceMarginPercentageString); - } else { - onePlusMaintenanceMarginPercentageString = Precise.stringSub ('-1', maintenanceMarginPercentageString); - entryPriceSignString = Precise.stringMul ('-1', entryPriceSignString); - } - const leftSide = Precise.stringMul (contractsAbs, contractSizeString); - const rightSide = Precise.stringSub (Precise.stringDiv ('1', entryPriceSignString), Precise.stringDiv (onePlusMaintenanceMarginPercentageString, liquidationPriceString)); - const basePrecision = this.safeInteger (precision, 'base'); - if (basePrecision !== undefined) { - collateralString = Precise.stringDiv (Precise.stringMul (leftSide, rightSide), '1', basePrecision); - } - } - } else { - collateralString = this.safeString (position, 'isolatedMargin'); - } - collateralString = (collateralString === undefined) ? '0' : collateralString; - const collateral = this.parseNumber (collateralString); - const markPrice = this.parseNumber (this.omitZero (this.safeString (position, 'markPrice'))); - let timestamp = this.safeInteger (position, 'updateTime'); - if (timestamp === 0) { - timestamp = undefined; - } - const maintenanceMarginPercentage = this.parseNumber (maintenanceMarginPercentageString); - const maintenanceMarginString = Precise.stringMul (maintenanceMarginPercentageString, notionalStringAbs); - const maintenanceMargin = this.parseNumber (maintenanceMarginString); - let initialMarginPercentageString = Precise.stringDiv ('1', leverageString, 8); - const rational = this.isRoundNumber (1000 % leverage); - if (!rational) { - initialMarginPercentageString = Precise.stringAdd (initialMarginPercentageString, '1e-8'); - } - const initialMarginString = Precise.stringDiv (Precise.stringMul (notionalStringAbs, initialMarginPercentageString), '1', 8); - const initialMargin = this.parseNumber (initialMarginString); - let marginRatio = undefined; - let percentage = undefined; - if (!Precise.stringEquals (collateralString, '0')) { - marginRatio = this.parseNumber (Precise.stringDiv (Precise.stringAdd (Precise.stringDiv (maintenanceMarginString, collateralString), '5e-5'), '1', 4)); - percentage = this.parseNumber (Precise.stringMul (Precise.stringDiv (unrealizedPnlString, initialMarginString, 4), '100')); - } - const positionSide = this.safeString (position, 'positionSide'); - const hedged = positionSide !== 'BOTH'; - return { - 'info': position, - 'id': undefined, - 'symbol': symbol, - 'contracts': contracts, - 'contractSize': contractSize, - 'unrealizedPnl': unrealizedPnl, - 'leverage': this.parseNumber (leverageString), - 'liquidationPrice': liquidationPrice, - 'collateral': collateral, - 'notional': notional, - 'markPrice': markPrice, - 'entryPrice': entryPrice, - 'timestamp': timestamp, - 'initialMargin': initialMargin, - 'initialMarginPercentage': this.parseNumber (initialMarginPercentageString), - 'maintenanceMargin': maintenanceMargin, - 'maintenanceMarginPercentage': maintenanceMarginPercentage, - 'marginRatio': marginRatio, - 'datetime': this.iso8601 (timestamp), - 'marginMode': marginMode, - 'marginType': marginMode, // deprecated - 'side': side, - 'hedged': hedged, - 'percentage': percentage, - 'stopLossPrice': undefined, - 'takeProfitPrice': undefined, - }; - } - - async loadLeverageBrackets (reload = false, params = {}) { - await this.loadMarkets (); - // by default cache the leverage bracket - // it contains useful stuff like the maintenance margin and initial margin for positions - const leverageBrackets = this.safeValue (this.options, 'leverageBrackets'); - if ((leverageBrackets === undefined) || (reload)) { - let method = undefined; - const defaultType = this.safeString (this.options, 'defaultType', 'future'); - const type = this.safeString (params, 'type', defaultType); - const query = this.omit (params, 'type'); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('loadLeverageBrackets', undefined, params, 'linear'); - if (this.isLinear (type, subType)) { - method = 'fapiPrivateGetLeverageBracket'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateV2GetLeverageBracket'; - } else { - throw new NotSupported (this.id + ' loadLeverageBrackets() supports linear and inverse contracts only'); - } - const response = await this[method] (query); - this.options['leverageBrackets'] = {}; - for (let i = 0; i < response.length; i++) { - const entry = response[i]; - const marketId = this.safeString (entry, 'symbol'); - const symbol = this.safeSymbol (marketId, undefined, undefined, 'contract'); - const brackets = this.safeValue (entry, 'brackets', []); - const result = []; - for (let j = 0; j < brackets.length; j++) { - const bracket = brackets[j]; - const floorValue = this.safeString2 (bracket, 'notionalFloor', 'qtyFloor'); - const maintenanceMarginPercentage = this.safeString (bracket, 'maintMarginRatio'); - result.push ([ floorValue, maintenanceMarginPercentage ]); - } - this.options['leverageBrackets'][symbol] = result; - } - } - return this.options['leverageBrackets']; - } - - async fetchLeverageTiers (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchLeverageTiers - * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes - * @see https://binance-docs.github.io/apidocs/futures/en/#notional-and-leverage-brackets-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#notional-bracket-for-symbol-user_data - * @param {string[]|undefined} symbols list of unified market symbols - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}, indexed by market symbols - */ - await this.loadMarkets (); - const [ type, query ] = this.handleMarketTypeAndParams ('fetchLeverageTiers', undefined, params); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchLeverageTiers', undefined, query, 'linear'); - let method = undefined; - if (this.isLinear (type, subType)) { - method = 'fapiPrivateGetLeverageBracket'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateV2GetLeverageBracket'; - } else { - throw new NotSupported (this.id + ' fetchLeverageTiers() supports linear and inverse contracts only'); - } - const response = await this[method] (query); - // - // usdm - // - // [ - // { - // "symbol": "SUSHIUSDT", - // "brackets": [ - // { - // "bracket": 1, - // "initialLeverage": 50, - // "notionalCap": 50000, - // "notionalFloor": 0, - // "maintMarginRatio": 0.01, - // "cum": 0.0 - // }, - // ... - // ] - // } - // ] - // - // coinm - // - // [ - // { - // "symbol":"XRPUSD_210326", - // "brackets":[ - // { - // "bracket":1, - // "initialLeverage":20, - // "qtyCap":500000, - // "qtyFloor":0, - // "maintMarginRatio":0.0185, - // "cum":0.0 - // } - // ] - // } - // ] - // - return this.parseLeverageTiers (response, symbols, 'symbol'); - } - - parseMarketLeverageTiers (info, market: Market = undefined) { - /** - * @ignore - * @method - * @param {object} info Exchange response for 1 market - * @param {object} market CCXT market - */ - // - // { - // "symbol": "SUSHIUSDT", - // "brackets": [ - // { - // "bracket": 1, - // "initialLeverage": 50, - // "notionalCap": 50000, - // "notionalFloor": 0, - // "maintMarginRatio": 0.01, - // "cum": 0.0 - // }, - // ... - // ] - // } - // - const marketId = this.safeString (info, 'symbol'); - market = this.safeMarket (marketId, market, undefined, 'contract'); - const brackets = this.safeValue (info, 'brackets', []); - const tiers = []; - for (let j = 0; j < brackets.length; j++) { - const bracket = brackets[j]; - tiers.push ({ - 'tier': this.safeNumber (bracket, 'bracket'), - 'currency': market['quote'], - 'minNotional': this.safeNumber2 (bracket, 'notionalFloor', 'qtyFloor'), - 'maxNotional': this.safeNumber2 (bracket, 'notionalCap', 'qtyCap'), - 'maintenanceMarginRate': this.safeNumber (bracket, 'maintMarginRatio'), - 'maxLeverage': this.safeNumber (bracket, 'initialLeverage'), - 'info': bracket, - }); - } - return tiers; - } - - async fetchPosition (symbol: string, params = {}) { - /** - * @method - * @name binance#fetchPosition - * @see https://binance-docs.github.io/apidocs/voptions/en/#option-position-information-user_data - * @description fetch data on an open position - * @param {string} symbol unified market symbol of the market the position is held in - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - if (!market['option']) { - throw new NotSupported (this.id + ' fetchPosition() supports option markets only'); - } - const request = { - 'symbol': market['id'], - }; - const response = await this.eapiPrivateGetPosition (this.extend (request, params)); - // - // [ - // { - // "entryPrice": "27.70000000", - // "symbol": "ETH-230426-1850-C", - // "side": "LONG", - // "quantity": "0.50000000", - // "reducibleQty": "0.50000000", - // "markValue": "10.250000000", - // "ror": "-0.2599", - // "unrealizedPNL": "-3.600000000", - // "markPrice": "20.5", - // "strikePrice": "1850.00000000", - // "positionCost": "13.85000000", - // "expiryDate": 1682496000000, - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT", - // "time": 1682492427106 - // } - // ] - // - return this.parsePosition (response[0], market); - } - - async fetchOptionPositions (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchOptionPositions - * @see https://binance-docs.github.io/apidocs/voptions/en/#option-position-information-user_data - * @description fetch data on open options positions - * @param {string[]|undefined} symbols list of unified market symbols - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure} - */ - await this.loadMarkets (); - symbols = this.marketSymbols (symbols); - const request = {}; - let market = undefined; - if (symbols !== undefined) { - let symbol = undefined; - if (Array.isArray (symbols)) { - const symbolsLength = symbols.length; - if (symbolsLength > 1) { - throw new BadRequest (this.id + ' fetchPositions() symbols argument cannot contain more than 1 symbol'); - } - symbol = symbols[0]; - } else { - symbol = symbols; - } - market = this.market (symbol); - request['symbol'] = market['id']; - } - const response = await this.eapiPrivateGetPosition (this.extend (request, params)); - // - // [ - // { - // "entryPrice": "27.70000000", - // "symbol": "ETH-230426-1850-C", - // "side": "LONG", - // "quantity": "0.50000000", - // "reducibleQty": "0.50000000", - // "markValue": "10.250000000", - // "ror": "-0.2599", - // "unrealizedPNL": "-3.600000000", - // "markPrice": "20.5", - // "strikePrice": "1850.00000000", - // "positionCost": "13.85000000", - // "expiryDate": 1682496000000, - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT", - // "time": 1682492427106 - // } - // ] - // - const result = []; - for (let i = 0; i < response.length; i++) { - result.push (this.parsePosition (response[i], market)); - } - return this.filterByArrayPositions (result, 'symbol', symbols, false); - } - - parsePosition (position, market: Market = undefined) { - // - // { - // "entryPrice": "27.70000000", - // "symbol": "ETH-230426-1850-C", - // "side": "LONG", - // "quantity": "0.50000000", - // "reducibleQty": "0.50000000", - // "markValue": "10.250000000", - // "ror": "-0.2599", - // "unrealizedPNL": "-3.600000000", - // "markPrice": "20.5", - // "strikePrice": "1850.00000000", - // "positionCost": "13.85000000", - // "expiryDate": 1682496000000, - // "priceScale": 1, - // "quantityScale": 2, - // "optionSide": "CALL", - // "quoteAsset": "USDT", - // "time": 1682492427106 - // } - // - const marketId = this.safeString (position, 'symbol'); - market = this.safeMarket (marketId, market); - const symbol = market['symbol']; - const side = this.safeStringLower (position, 'side'); - let quantity = this.safeString (position, 'quantity'); - if (side !== 'long') { - quantity = Precise.stringMul ('-1', quantity); - } - const timestamp = this.safeInteger (position, 'time'); - return this.safePosition ({ - 'info': position, - 'id': undefined, - 'symbol': symbol, - 'entryPrice': this.safeNumber (position, 'entryPrice'), - 'markPrice': this.safeNumber (position, 'markPrice'), - 'notional': this.safeNumber (position, 'markValue'), - 'collateral': this.safeNumber (position, 'positionCost'), - 'unrealizedPnl': this.safeNumber (position, 'unrealizedPNL'), - 'side': side, - 'contracts': this.parseNumber (quantity), - 'contractSize': undefined, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'hedged': undefined, - 'maintenanceMargin': undefined, - 'maintenanceMarginPercentage': undefined, - 'initialMargin': undefined, - 'initialMarginPercentage': undefined, - 'leverage': undefined, - 'liquidationPrice': undefined, - 'marginRatio': undefined, - 'marginMode': undefined, - 'percentage': undefined, - }); - } - - async fetchPositions (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchPositions - * @description fetch all open positions - * @param {string[]|undefined} symbols list of unified market symbols - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} - */ - const defaultMethod = this.safeString (this.options, 'fetchPositions', 'positionRisk'); - if (defaultMethod === 'positionRisk') { - return await this.fetchPositionsRisk (symbols, params); - } else if (defaultMethod === 'account') { - return await this.fetchAccountPositions (symbols, params); - } else if (defaultMethod === 'option') { - return await this.fetchOptionPositions (symbols, params); - } else { - throw new NotSupported (this.id + '.options["fetchPositions"] = "' + defaultMethod + '" is invalid, please choose between "account", "positionRisk" and "option"'); - } - } - - async fetchAccountPositions (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchAccountPositions - * @ignore - * @description fetch account positions - * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-v2-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data - * @param {string[]|undefined} symbols list of unified market symbols - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} data on account positions - */ - if (symbols !== undefined) { - if (!Array.isArray (symbols)) { - throw new ArgumentsRequired (this.id + ' fetchPositions() requires an array argument for symbols'); - } - } - await this.loadMarkets (); - await this.loadLeverageBrackets (false, params); - let method = undefined; - const defaultType = this.safeString (this.options, 'defaultType', 'future'); - const type = this.safeString (params, 'type', defaultType); - let query = this.omit (params, 'type'); - let subType = undefined; - [ subType, query ] = this.handleSubTypeAndParams ('fetchAccountPositions', undefined, params, 'linear'); - if (this.isLinear (type, subType)) { - method = 'fapiPrivateV2GetAccount'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateGetAccount'; - } else { - throw new NotSupported (this.id + ' fetchPositions() supports linear and inverse contracts only'); - } - const account = await this[method] (query); - const result = this.parseAccountPositions (account); - symbols = this.marketSymbols (symbols); - return this.filterByArrayPositions (result, 'symbol', symbols, false); - } - - async fetchPositionsRisk (symbols: Strings = undefined, params = {}) { - /** - * @method - * @name binance#fetchPositionsRisk - * @ignore - * @description fetch positions risk - * @see https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#position-information-user_data - * @param {string[]|undefined} symbols list of unified market symbols - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} data on the positions risk - */ - if (symbols !== undefined) { - if (!Array.isArray (symbols)) { - throw new ArgumentsRequired (this.id + ' fetchPositionsRisk() requires an array argument for symbols'); - } - } - await this.loadMarkets (); - await this.loadLeverageBrackets (false, params); - const request = {}; - let method = undefined; - let defaultType = 'future'; - defaultType = this.safeString (this.options, 'defaultType', defaultType); - const type = this.safeString (params, 'type', defaultType); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchPositionsRisk', undefined, params, 'linear'); - params = this.omit (params, 'type'); - if (this.isLinear (type, subType)) { - method = 'fapiPrivateV2GetPositionRisk'; - // ### Response examples ### - // - // For One-way position mode: - // [ - // { - // "entryPrice": "0.00000", - // "marginType": "isolated", - // "isAutoAddMargin": "false", - // "isolatedMargin": "0.00000000", - // "leverage": "10", - // "liquidationPrice": "0", - // "markPrice": "6679.50671178", - // "maxNotionalValue": "20000000", - // "positionAmt": "0.000", - // "symbol": "BTCUSDT", - // "unRealizedProfit": "0.00000000", - // "positionSide": "BOTH", - // "updateTime": 0 - // } - // ] - // - // For Hedge position mode: - // [ - // { - // "entryPrice": "6563.66500", - // "marginType": "isolated", - // "isAutoAddMargin": "false", - // "isolatedMargin": "15517.54150468", - // "leverage": "10", - // "liquidationPrice": "5930.78", - // "markPrice": "6679.50671178", - // "maxNotionalValue": "20000000", - // "positionAmt": "20.000", - // "symbol": "BTCUSDT", - // "unRealizedProfit": "2316.83423560" - // "positionSide": "LONG", - // "updateTime": 1625474304765 - // }, - // { - // "entryPrice": "0.00000", - // "marginType": "isolated", - // "isAutoAddMargin": "false", - // "isolatedMargin": "5413.95799991", - // "leverage": "10", - // "liquidationPrice": "7189.95", - // "markPrice": "6679.50671178", - // "maxNotionalValue": "20000000", - // "positionAmt": "-10.000", - // "symbol": "BTCUSDT", - // "unRealizedProfit": "-1156.46711780", - // "positionSide": "SHORT", - // "updateTime": 0 - // } - // ] - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateGetPositionRisk'; - } else { - throw new NotSupported (this.id + ' fetchPositionsRisk() supports linear and inverse contracts only'); - } - const response = await this[method] (this.extend (request, params)); - const result = []; - for (let i = 0; i < response.length; i++) { - const parsed = this.parsePositionRisk (response[i]); - result.push (parsed); - } - symbols = this.marketSymbols (symbols); - return this.filterByArrayPositions (result, 'symbol', symbols, false); - } - - async fetchFundingHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchFundingHistory - * @description fetch the history of funding payments paid and received on this account - * @see https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data - * @param {string} symbol unified market symbol - * @param {int} [since] the earliest time in ms to fetch funding history for - * @param {int} [limit] the maximum number of funding history structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure} - */ - await this.loadMarkets (); - let market = undefined; - let method = undefined; - const request = { - 'incomeType': 'FUNDING_FEE', // "TRANSFER","WELCOME_BONUS", "REALIZED_PNL","FUNDING_FEE", "COMMISSION" and "INSURANCE_CLEAR" - }; - if (symbol !== undefined) { - market = this.market (symbol); - request['symbol'] = market['id']; - if (!market['swap']) { - throw new NotSupported (this.id + ' fetchFundingHistory() supports swap contracts only'); - } - } - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchFundingHistory', market, params, 'linear'); - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['limit'] = limit; - } - const defaultType = this.safeString2 (this.options, 'fetchFundingHistory', 'defaultType', 'future'); - const type = this.safeString (params, 'type', defaultType); - params = this.omit (params, 'type'); - if (this.isLinear (type, subType)) { - method = 'fapiPrivateGetIncome'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateGetIncome'; - } else { - throw new NotSupported (this.id + ' fetchFundingHistory() supports linear and inverse contracts only'); - } - const response = await this[method] (this.extend (request, params)); - return this.parseIncomes (response, market, since, limit); - } - - async setLeverage (leverage, symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#setLeverage - * @description set the level of leverage for a market - * @see https://binance-docs.github.io/apidocs/futures/en/#change-initial-leverage-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#change-initial-leverage-trade - * @param {float} leverage the rate of leverage - * @param {string} symbol unified market symbol - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} response from the exchange - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' setLeverage() requires a symbol argument'); - } - // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS - // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS - if ((leverage < 1) || (leverage > 125)) { - throw new BadRequest (this.id + ' leverage should be between 1 and 125'); - } - await this.loadMarkets (); - const market = this.market (symbol); - let method: string; - if (market['linear']) { - method = 'fapiPrivatePostLeverage'; - } else if (market['inverse']) { - method = 'dapiPrivatePostLeverage'; - } else { - throw new NotSupported (this.id + ' setLeverage() supports linear and inverse contracts only'); - } - const request = { - 'symbol': market['id'], - 'leverage': leverage, - }; - return await this[method] (this.extend (request, params)); - } - - async setMarginMode (marginMode: string, symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#setMarginMode - * @description set margin mode to 'cross' or 'isolated' - * @see https://binance-docs.github.io/apidocs/futures/en/#change-margin-type-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#change-margin-type-trade - * @param {string} marginMode 'cross' or 'isolated' - * @param {string} symbol unified market symbol - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} response from the exchange - */ - if (symbol === undefined) { - throw new ArgumentsRequired (this.id + ' setMarginMode() requires a symbol argument'); - } - // - // { "code": -4048 , "msg": "Margin type cannot be changed if there exists position." } - // - // or - // - // { "code": 200, "msg": "success" } - // - marginMode = marginMode.toUpperCase (); - if (marginMode === 'CROSS') { - marginMode = 'CROSSED'; - } - if ((marginMode !== 'ISOLATED') && (marginMode !== 'CROSSED')) { - throw new BadRequest (this.id + ' marginMode must be either isolated or cross'); - } - await this.loadMarkets (); - const market = this.market (symbol); - let method = undefined; - if (market['linear']) { - method = 'fapiPrivatePostMarginType'; - } else if (market['inverse']) { - method = 'dapiPrivatePostMarginType'; - } else { - throw new NotSupported (this.id + ' setMarginMode() supports linear and inverse contracts only'); - } - const request = { - 'symbol': market['id'], - 'marginType': marginMode, - }; - let response = undefined; - try { - response = await this[method] (this.extend (request, params)); - } catch (e) { - // not an error - // https://github.com/ccxt/ccxt/issues/11268 - // https://github.com/ccxt/ccxt/pull/11624 - // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request - // binanceusdm - if (e instanceof MarginModeAlreadySet) { - const throwMarginModeAlreadySet = this.safeValue (this.options, 'throwMarginModeAlreadySet', false); - if (throwMarginModeAlreadySet) { - throw e; - } else { - response = { 'code': -4046, 'msg': 'No need to change margin type.' }; - } - } else { - throw e; - } - } - return response; - } - - async setPositionMode (hedged, symbol: Str = undefined, params = {}) { - /** - * @method - * @name binance#setPositionMode - * @description set hedged to true or false for a market - * @see https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade - * @see https://binance-docs.github.io/apidocs/delivery/en/#change-position-mode-trade - * @param {bool} hedged set to true to use dualSidePosition - * @param {string} symbol not used by binance setPositionMode () - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} response from the exchange - */ - const defaultType = this.safeString (this.options, 'defaultType', 'future'); - const type = this.safeString (params, 'type', defaultType); - params = this.omit (params, [ 'type' ]); - let dualSidePosition = undefined; - if (hedged) { - dualSidePosition = 'true'; - } else { - dualSidePosition = 'false'; - } - const request = { - 'dualSidePosition': dualSidePosition, - }; - let method = undefined; - if (this.isInverse (type)) { - method = 'dapiPrivatePostPositionSideDual'; - } else { - // default to future - method = 'fapiPrivatePostPositionSideDual'; - } - // - // { - // "code": 200, - // "msg": "success" - // } - // - return await this[method] (this.extend (request, params)); - } - - async fetchSettlementHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchSettlementHistory - * @description fetches historical settlement records - * @see https://binance-docs.github.io/apidocs/voptions/en/#historical-exercise-records - * @param {string} symbol unified market symbol of the settlement history - * @param {int} [since] timestamp in ms - * @param {int} [limit] number of records, default 100, max 100 - * @param {object} [params] exchange specific params - * @returns {object[]} a list of [settlement history objects]{@link https://docs.ccxt.com/#/?id=settlement-history-structure} - */ - await this.loadMarkets (); - const market = (symbol === undefined) ? undefined : this.market (symbol); - let type = undefined; - [ type, params ] = this.handleMarketTypeAndParams ('fetchSettlementHistory', market, params); - if (type !== 'option') { - throw new NotSupported (this.id + ' fetchSettlementHistory() supports option markets only'); - } - const request = {}; - if (symbol !== undefined) { - symbol = market['symbol']; - request['underlying'] = market['baseId'] + market['quoteId']; - } - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['limit'] = limit; - } - const response = await this.eapiPublicGetExerciseHistory (this.extend (request, params)); - // - // [ - // { - // "symbol": "ETH-230223-1900-P", - // "strikePrice": "1900", - // "realStrikePrice": "1665.5897334", - // "expiryDate": 1677139200000, - // "strikeResult": "REALISTIC_VALUE_STRICKEN" - // } - // ] - // - const settlements = this.parseSettlements (response, market); - const sorted = this.sortBy (settlements, 'timestamp'); - return this.filterBySymbolSinceLimit (sorted, symbol, since, limit); - } - - async fetchMySettlementHistory (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchMySettlementHistory - * @description fetches historical settlement records of the user - * @see https://binance-docs.github.io/apidocs/voptions/en/#user-exercise-record-user_data - * @param {string} symbol unified market symbol of the settlement history - * @param {int} [since] timestamp in ms - * @param {int} [limit] number of records - * @param {object} [params] exchange specific params - * @returns {object[]} a list of [settlement history objects] - */ - await this.loadMarkets (); - const market = (symbol === undefined) ? undefined : this.market (symbol); - let type = undefined; - [ type, params ] = this.handleMarketTypeAndParams ('fetchMySettlementHistory', market, params); - if (type !== 'option') { - throw new NotSupported (this.id + ' fetchMySettlementHistory() supports option markets only'); - } - const request = {}; - if (symbol !== undefined) { - request['symbol'] = market['id']; - } - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['limit'] = limit; - } - const response = await this.eapiPrivateGetExerciseRecord (this.extend (request, params)); - // - // [ - // { - // "id": "1125899906842897036", - // "currency": "USDT", - // "symbol": "BTC-230728-30000-C", - // "exercisePrice": "30000.00000000", - // "markPrice": "29160.71284993", - // "quantity": "1.00000000", - // "amount": "0.00000000", - // "fee": "0.00000000", - // "createDate": 1690531200000, - // "priceScale": 0, - // "quantityScale": 2, - // "optionSide": "CALL", - // "positionSide": "LONG", - // "quoteAsset": "USDT" - // } - // ] - // - const settlements = this.parseSettlements (response, market); - const sorted = this.sortBy (settlements, 'timestamp'); - return this.filterBySymbolSinceLimit (sorted, market['symbol'], since, limit); - } - - parseSettlement (settlement, market) { - // - // fetchSettlementHistory - // - // { - // "symbol": "ETH-230223-1900-P", - // "strikePrice": "1900", - // "realStrikePrice": "1665.5897334", - // "expiryDate": 1677139200000, - // "strikeResult": "REALISTIC_VALUE_STRICKEN" - // } - // - // fetchMySettlementHistory - // - // { - // "id": "1125899906842897036", - // "currency": "USDT", - // "symbol": "BTC-230728-30000-C", - // "exercisePrice": "30000.00000000", - // "markPrice": "29160.71284993", - // "quantity": "1.00000000", - // "amount": "0.00000000", - // "fee": "0.00000000", - // "createDate": 1690531200000, - // "priceScale": 0, - // "quantityScale": 2, - // "optionSide": "CALL", - // "positionSide": "LONG", - // "quoteAsset": "USDT" - // } - // - const timestamp = this.safeInteger2 (settlement, 'expiryDate', 'createDate'); - const marketId = this.safeString (settlement, 'symbol'); - return { - 'info': settlement, - 'symbol': this.safeSymbol (marketId, market), - 'price': this.safeNumber2 (settlement, 'realStrikePrice', 'exercisePrice'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - }; - } - - parseSettlements (settlements, market) { - // - // fetchSettlementHistory - // - // [ - // { - // "symbol": "ETH-230223-1900-P", - // "strikePrice": "1900", - // "realStrikePrice": "1665.5897334", - // "expiryDate": 1677139200000, - // "strikeResult": "EXTRINSIC_VALUE_EXPIRED" - // } - // ] - // - // fetchMySettlementHistory - // - // [ - // { - // "id": "1125899906842897036", - // "currency": "USDT", - // "symbol": "BTC-230728-30000-C", - // "exercisePrice": "30000.00000000", - // "markPrice": "29160.71284993", - // "quantity": "1.00000000", - // "amount": "0.00000000", - // "fee": "0.00000000", - // "createDate": 1690531200000, - // "priceScale": 0, - // "quantityScale": 2, - // "optionSide": "CALL", - // "positionSide": "LONG", - // "quoteAsset": "USDT" - // } - // ] - // - const result = []; - for (let i = 0; i < settlements.length; i++) { - result.push (this.parseSettlement (settlements[i], market)); - } - return result; - } - - async fetchLedger (code: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchLedger - * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user - * @see https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data - * @param {string} code unified currency code - * @param {int} [since] timestamp in ms of the earliest ledger entry - * @param {int} [limit] max number of ledger entrys to return - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @param {int} [params.until] timestamp in ms of the latest ledger entry - * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger-structure} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchLedger', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallDynamic ('fetchLedger', code, since, limit, params); - } - let type = undefined; - let subType = undefined; - let currency = undefined; - if (code !== undefined) { - currency = this.currency (code); - } - let method = undefined; - const request = {}; - [ type, params ] = this.handleMarketTypeAndParams ('fetchLedger', undefined, params); - [ subType, params ] = this.handleSubTypeAndParams ('fetchLedger', undefined, params); - if (type === 'option') { - this.checkRequiredArgument ('fetchLedger', code, 'code'); - request['currency'] = currency['id']; - method = 'eapiPrivateGetBill'; - } else if (this.isLinear (type, subType)) { - method = 'fapiPrivateGetIncome'; - } else if (this.isInverse (type, subType)) { - method = 'dapiPrivateGetIncome'; - } else { - throw new NotSupported (this.id + ' fetchLedger() supports contract wallets only'); - } - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['limit'] = limit; - } - const until = this.safeInteger (params, 'until'); - if (until !== undefined) { - params = this.omit (params, 'until'); - request['endTime'] = until; - } - const response = await this[method] (this.extend (request, params)); - // - // options (eapi) - // - // [ - // { - // "id": "1125899906845701870", - // "asset": "USDT", - // "amount": "-0.16518203", - // "type": "FEE", - // "createDate": 1676621042489 - // } - // ] - // - // futures (fapi, dapi) - // - // [ - // { - // "symbol": "", - // "incomeType": "TRANSFER", - // "income": "10.00000000", - // "asset": "USDT", - // "time": 1677645250000, - // "info": "TRANSFER", - // "tranId": 131001573082, - // "tradeId": "" - // } - // ] - // - return this.parseLedger (response, currency, since, limit); - } - - parseLedgerEntry (item, currency: Currency = undefined) { - // - // options (eapi) - // - // { - // "id": "1125899906845701870", - // "asset": "USDT", - // "amount": "-0.16518203", - // "type": "FEE", - // "createDate": 1676621042489 - // } - // - // futures (fapi, dapi) - // - // { - // "symbol": "", - // "incomeType": "TRANSFER", - // "income": "10.00000000", - // "asset": "USDT", - // "time": 1677645250000, - // "info": "TRANSFER", - // "tranId": 131001573082, - // "tradeId": "" - // } - // - let amount = this.safeString2 (item, 'amount', 'income'); - let direction = undefined; - if (Precise.stringLe (amount, '0')) { - direction = 'out'; - amount = Precise.stringMul ('-1', amount); - } else { - direction = 'in'; - } - const currencyId = this.safeString (item, 'asset'); - const timestamp = this.safeInteger2 (item, 'createDate', 'time'); - const type = this.safeString2 (item, 'type', 'incomeType'); - return { - 'id': this.safeString2 (item, 'id', 'tranId'), - 'direction': direction, - 'account': undefined, - 'referenceAccount': undefined, - 'referenceId': this.safeString (item, 'tradeId'), - 'type': this.parseLedgerEntryType (type), - 'currency': this.safeCurrencyCode (currencyId, currency), - 'amount': this.parseNumber (amount), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'before': undefined, - 'after': undefined, - 'status': undefined, - 'fee': undefined, - 'info': item, - }; - } - - parseLedgerEntryType (type) { - const ledgerType = { - 'FEE': 'fee', - 'FUNDING_FEE': 'fee', - 'OPTIONS_PREMIUM_FEE': 'fee', - 'POSITION_LIMIT_INCREASE_FEE': 'fee', - 'CONTRACT': 'trade', - 'REALIZED_PNL': 'trade', - 'TRANSFER': 'transfer', - 'CROSS_COLLATERAL_TRANSFER': 'transfer', - 'INTERNAL_TRANSFER': 'transfer', - 'COIN_SWAP_DEPOSIT': 'deposit', - 'COIN_SWAP_WITHDRAW': 'withdrawal', - 'OPTIONS_SETTLE_PROFIT': 'settlement', - 'DELIVERED_SETTELMENT': 'settlement', - 'WELCOME_BONUS': 'cashback', - 'CONTEST_REWARD': 'cashback', - 'COMMISSION_REBATE': 'rebate', - 'API_REBATE': 'rebate', - 'REFERRAL_KICKBACK': 'referral', - 'COMMISSION': 'commission', - }; - return this.safeString (ledgerType, type, type); - } - - sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { - const urls = this.urls as any; - if (!(api in urls['api'])) { - throw new NotSupported (this.id + ' does not have a testnet/sandbox URL for ' + api + ' endpoints'); - } - let url = this.urls['api'][api]; - url += '/' + path; - if (path === 'historicalTrades') { - if (this.apiKey) { - headers = { - 'X-MBX-APIKEY': this.apiKey, - }; - } else { - throw new AuthenticationError (this.id + ' historicalTrades endpoint requires `apiKey` credential'); - } - } - const userDataStream = (path === 'userDataStream') || (path === 'listenKey'); - if (userDataStream) { - if (this.apiKey) { - // v1 special case for userDataStream - headers = { - 'X-MBX-APIKEY': this.apiKey, - 'Content-Type': 'application/x-www-form-urlencoded', - }; - if (method !== 'GET') { - body = this.urlencode (params); - } - } else { - throw new AuthenticationError (this.id + ' userDataStream endpoint requires `apiKey` credential'); - } - } else if ((api === 'private') || (api === 'eapiPrivate') || (api === 'sapi' && path !== 'system/status') || (api === 'sapiV2') || (api === 'sapiV3') || (api === 'sapiV4') || (api === 'dapiPrivate') || (api === 'dapiPrivateV2') || (api === 'fapiPrivate') || (api === 'fapiPrivateV2') || (api === 'papi')) { - this.checkRequiredCredentials (); - if (method === 'POST' && ((path === 'order') || (path === 'sor/order'))) { - // inject in implicit API calls - const newClientOrderId = this.safeString (params, 'newClientOrderId'); - if (newClientOrderId === undefined) { - const isSpotOrMargin = (api.indexOf ('sapi') > -1 || api === 'private'); - const marketType = isSpotOrMargin ? 'spot' : 'future'; - const defaultId = (!isSpotOrMargin) ? 'x-xcKtGhcu' : 'x-R4BD3S82'; - const broker = this.safeValue (this.options, 'broker', {}); - const brokerId = this.safeString (broker, marketType, defaultId); - params['newClientOrderId'] = brokerId + this.uuid22 (); - } - } - let query = undefined; - // handle batchOrders - if ((path === 'batchOrders') && (method === 'POST')) { - const batchOrders = this.safeValue (params, 'batchOrders'); - const queryBatch = (this.json (batchOrders)); - params['batchOrders'] = queryBatch; - } - const defaultRecvWindow = this.safeInteger (this.options, 'recvWindow'); - let extendedParams = this.extend ({ - 'timestamp': this.nonce (), - }, params); - if (defaultRecvWindow !== undefined) { - extendedParams['recvWindow'] = defaultRecvWindow; - } - const recvWindow = this.safeInteger (params, 'recvWindow'); - if (recvWindow !== undefined) { - extendedParams['recvWindow'] = recvWindow; - } - if ((api === 'sapi') && (path === 'asset/dust')) { - query = this.urlencodeWithArrayRepeat (extendedParams); - } else if ((path === 'batchOrders') || (path.indexOf ('sub-account') >= 0) || (path === 'capital/withdraw/apply') || (path.indexOf ('staking') >= 0)) { - if ((method === 'DELETE') && (path === 'batchOrders')) { - const orderidlist = this.safeValue (extendedParams, 'orderidlist', []); - const origclientorderidlist = this.safeValue (extendedParams, 'origclientorderidlist', []); - extendedParams = this.omit (extendedParams, [ 'orderidlist', 'origclientorderidlist' ]); - query = this.rawencode (extendedParams); - const orderidlistLength = orderidlist.length; - const origclientorderidlistLength = origclientorderidlist.length; - if (orderidlistLength > 0) { - query = query + '&' + 'orderidlist=[' + orderidlist.join (',') + ']'; - } - if (origclientorderidlistLength > 0) { - query = query + '&' + 'origclientorderidlist=[' + origclientorderidlist.join (',') + ']'; - } - } else { - query = this.rawencode (extendedParams); - } - } else { - query = this.urlencode (extendedParams); - } - let signature = undefined; - if (this.secret.indexOf ('PRIVATE KEY') > -1) { - if (this.secret.length > 120) { - signature = this.encodeURIComponent (rsa (query, this.secret, sha256)); - } else { - signature = this.encodeURIComponent (eddsa (this.encode (query), this.secret, ed25519)); - } - } else { - signature = this.hmac (this.encode (query), this.encode (this.secret), sha256); - } - query += '&' + 'signature=' + signature; - headers = { - 'X-MBX-APIKEY': this.apiKey, - }; - if ((method === 'GET') || (method === 'DELETE')) { - url += '?' + query; - } else { - body = query; - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } - } else { - if (Object.keys (params).length) { - url += '?' + this.urlencode (params); - } - } - return { 'url': url, 'method': method, 'body': body, 'headers': headers }; - } - - handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) { - if ((code === 418) || (code === 429)) { - throw new DDoSProtection (this.id + ' ' + code.toString () + ' ' + reason + ' ' + body); - } - // error response in a form: { "code": -1013, "msg": "Invalid quantity." } - // following block cointains legacy checks against message patterns in "msg" property - // will switch "code" checks eventually, when we know all of them - if (code >= 400) { - if (body.indexOf ('Price * QTY is zero or less') >= 0) { - throw new InvalidOrder (this.id + ' order cost = amount * price is zero or less ' + body); - } - if (body.indexOf ('LOT_SIZE') >= 0) { - throw new InvalidOrder (this.id + ' order amount should be evenly divisible by lot size ' + body); - } - if (body.indexOf ('PRICE_FILTER') >= 0) { - throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid value in general, use this.priceToPrecision (symbol, amount) ' + body); - } - } - if (response === undefined) { - return undefined; // fallback to default error handler - } - // response in format {'msg': 'The coin does not exist.', 'success': true/false} - const success = this.safeValue (response, 'success', true); - if (!success) { - const messageNew = this.safeString (response, 'msg'); - let parsedMessage = undefined; - if (messageNew !== undefined) { - try { - parsedMessage = JSON.parse (messageNew); - } catch (e) { - // do nothing - parsedMessage = undefined; - } - if (parsedMessage !== undefined) { - response = parsedMessage; - } - } - } - const message = this.safeString (response, 'msg'); - if (message !== undefined) { - this.throwExactlyMatchedException (this.exceptions['exact'], message, this.id + ' ' + message); - this.throwBroadlyMatchedException (this.exceptions['broad'], message, this.id + ' ' + message); - } - // checks against error codes - const error = this.safeString (response, 'code'); - if (error !== undefined) { - // https://github.com/ccxt/ccxt/issues/6501 - // https://github.com/ccxt/ccxt/issues/7742 - if ((error === '200') || Precise.stringEquals (error, '0')) { - return undefined; - } - // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} - // despite that their message is very confusing, it is raised by Binance - // on a temporary ban, the API key is valid, but disabled for a while - if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) { - throw new DDoSProtection (this.id + ' ' + body); - } - const feedback = this.id + ' ' + body; - if (message === 'No need to change margin type.') { - // not an error - // https://github.com/ccxt/ccxt/issues/11268 - // https://github.com/ccxt/ccxt/pull/11624 - // POST https://fapi.binance.com/fapi/v1/marginType 400 Bad Request - // binanceusdm {"code":-4046,"msg":"No need to change margin type."} - throw new MarginModeAlreadySet (feedback); - } - this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback); - throw new ExchangeError (feedback); - } - if (!success) { - throw new ExchangeError (this.id + ' ' + body); - } - if (Array.isArray (response)) { - // cancelOrders returns an array like this: [{"code":-2011,"msg":"Unknown order sent."}] - const arrayLength = response.length; - if (arrayLength === 1) { // when there's a single error we can throw, otherwise we have a partial success - const element = response[0]; - const errorCode = this.safeString (element, 'code'); - if (errorCode !== undefined) { - this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, this.id + ' ' + body); - } - } - } - return undefined; - } - - calculateRateLimiterCost (api, method, path, params, config = {}) { - if (('noCoin' in config) && !('coin' in params)) { - return config['noCoin']; - } else if (('noSymbol' in config) && !('symbol' in params)) { - return config['noSymbol']; - } else if (('noPoolId' in config) && !('poolId' in params)) { - return config['noPoolId']; - } else if (('byLimit' in config) && ('limit' in params)) { - const limit = params['limit']; - const byLimit = config['byLimit'] as any; - for (let i = 0; i < byLimit.length; i++) { - const entry = byLimit[i]; - if (limit <= entry[0]) { - return entry[1]; - } - } - } - return this.safeValue (config, 'cost', 1); - } - - async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined, config = {}, context = {}) { - const response = await this.fetch2 (path, api, method, params, headers, body, config); - // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."} - if (api === 'private') { - this.options['hasAlreadyAuthenticatedSuccessfully'] = true; - } - return response; - } - - async modifyMarginHelper (symbol: string, amount, addOrReduce, params = {}) { - // used to modify isolated positions - let defaultType = this.safeString (this.options, 'defaultType', 'future'); - if (defaultType === 'spot') { - defaultType = 'future'; - } - const type = this.safeString (params, 'type', defaultType); - if ((type === 'margin') || (type === 'spot')) { - throw new NotSupported (this.id + ' add / reduce margin only supported with type future or delivery'); - } - await this.loadMarkets (); - const market = this.market (symbol); - amount = this.costToPrecision (symbol, amount); - const request = { - 'type': addOrReduce, - 'symbol': market['id'], - 'amount': amount, - }; - let method = undefined; - let code = undefined; - if (market['linear']) { - method = 'fapiPrivatePostPositionMargin'; - code = market['quote']; - } else { - method = 'dapiPrivatePostPositionMargin'; - code = market['base']; - } - const response = await this[method] (this.extend (request, params)); - // - // { - // "code": 200, - // "msg": "Successfully modify position margin.", - // "amount": 0.001, - // "type": 1 - // } - // - return this.extend (this.parseMarginModification (response, market), { - 'code': code, - }); - } - - parseMarginModification (data, market: Market = undefined) { - const rawType = this.safeInteger (data, 'type'); - const resultType = (rawType === 1) ? 'add' : 'reduce'; - const resultAmount = this.safeNumber (data, 'amount'); - const errorCode = this.safeString (data, 'code'); - const status = (errorCode === '200') ? 'ok' : 'failed'; - return { - 'info': data, - 'type': resultType, - 'amount': resultAmount, - 'code': undefined, - 'symbol': market['symbol'], - 'status': status, - }; - } - - async reduceMargin (symbol: string, amount, params = {}) { - /** - * @method - * @name binance#reduceMargin - * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-isolated-position-margin-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#modify-isolated-position-margin-trade - * @description remove margin from a position - * @param {string} symbol unified market symbol - * @param {float} amount the amount of margin to remove - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure} - */ - return await this.modifyMarginHelper (symbol, amount, 2, params); - } - - async addMargin (symbol: string, amount, params = {}) { - /** - * @method - * @name binance#addMargin - * @see https://binance-docs.github.io/apidocs/delivery/en/#modify-isolated-position-margin-trade - * @see https://binance-docs.github.io/apidocs/futures/en/#modify-isolated-position-margin-trade - * @description add margin - * @param {string} symbol unified market symbol - * @param {float} amount amount of margin to add - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure} - */ - return await this.modifyMarginHelper (symbol, amount, 1, params); - } - - async fetchCrossBorrowRate (code: string, params = {}) { - /** - * @method - * @name binance#fetchCrossBorrowRate - * @description fetch the rate of interest to borrow a currency for margin trading - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-interest-rate-history-user_data - * @param {string} code unified currency code - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [borrow rate structure]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'asset': currency['id'], - // 'vipLevel': this.safeInteger (params, 'vipLevel'), - }; - const response = await this.sapiGetMarginInterestRateHistory (this.extend (request, params)); - // - // [ - // { - // "asset": "USDT", - // "timestamp": 1638230400000, - // "dailyInterestRate": "0.0006", - // "vipLevel": 0 - // }, - // ] - // - const rate = this.safeValue (response, 0); - return this.parseBorrowRate (rate); - } - - async fetchBorrowRateHistory (code: string, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchBorrowRateHistory - * @description retrieves a history of a currencies borrow interest rate at specific time slots - * @see https://binance-docs.github.io/apidocs/spot/en/#query-margin-interest-rate-history-user_data - * @param {string} code unified currency code - * @param {int} [since] timestamp for the earliest borrow rate - * @param {int} [limit] the maximum number of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} an array of [borrow rate structures]{@link https://docs.ccxt.com/#/?id=borrow-rate-structure} - */ - await this.loadMarkets (); - if (limit === undefined) { - limit = 93; - } else if (limit > 93) { - // Binance API says the limit is 100, but "Illegal characters found in a parameter." is returned when limit is > 93 - throw new BadRequest (this.id + ' fetchBorrowRateHistory() limit parameter cannot exceed 92'); - } - const currency = this.currency (code); - const request = { - 'asset': currency['id'], - 'limit': limit, - }; - if (since !== undefined) { - request['startTime'] = since; - const endTime = this.sum (since, limit * 86400000) - 1; // required when startTime is further than 93 days in the past - const now = this.milliseconds (); - request['endTime'] = Math.min (endTime, now); // cannot have an endTime later than current time - } - const response = await this.sapiGetMarginInterestRateHistory (this.extend (request, params)); - // - // [ - // { - // "asset": "USDT", - // "timestamp": 1638230400000, - // "dailyInterestRate": "0.0006", - // "vipLevel": 0 - // }, - // ] - // - return this.parseBorrowRateHistory (response, code, since, limit); - } - - parseBorrowRateHistory (response, code, since, limit) { - const result = []; - for (let i = 0; i < response.length; i++) { - const item = response[i]; - const borrowRate = this.parseBorrowRate (item); - result.push (borrowRate); - } - const sorted = this.sortBy (result, 'timestamp'); - return this.filterByCurrencySinceLimit (sorted, code, since, limit); - } - - parseBorrowRate (info, currency: Currency = undefined) { - // - // { - // "asset": "USDT", - // "timestamp": 1638230400000, - // "dailyInterestRate": "0.0006", - // "vipLevel": 0 - // } - // - const timestamp = this.safeInteger (info, 'timestamp'); - const currencyId = this.safeString (info, 'asset'); - return { - 'currency': this.safeCurrencyCode (currencyId, currency), - 'rate': this.safeNumber (info, 'dailyInterestRate'), - 'period': 86400000, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'info': info, - }; - } - - async createGiftCode (code: string, amount, params = {}) { - /** - * @method - * @name binance#createGiftCode - * @description create gift code - * @see https://binance-docs.github.io/apidocs/spot/en/#create-a-single-token-gift-card-user_data - * @param {string} code gift code - * @param {float} amount amount of currency for the gift - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} The gift code id, code, currency and amount - */ - await this.loadMarkets (); - const currency = this.currency (code); - // ensure you have enough token in your funding account before calling this code - const request = { - 'token': currency['id'], - 'amount': amount, - }; - const response = await this.sapiPostGiftcardCreateCode (this.extend (request, params)); - // - // { - // "code": "000000", - // "message": "success", - // "data": { referenceNo: "0033002404219823", code: "AP6EXTLKNHM6CEX7" }, - // "success": true - // } - // - const data = this.safeValue (response, 'data'); - const giftcardCode = this.safeString (data, 'code'); - const id = this.safeString (data, 'referenceNo'); - return { - 'info': response, - 'id': id, - 'code': giftcardCode, - 'currency': code, - 'amount': amount, - }; - } - - async redeemGiftCode (giftcardCode, params = {}) { - /** - * @method - * @name binance#redeemGiftCode - * @description redeem gift code - * @see https://binance-docs.github.io/apidocs/spot/en/#redeem-a-binance-gift-card-user_data - * @param {string} giftcardCode - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} response from the exchange - */ - const request = { - 'code': giftcardCode, - }; - const response = await this.sapiPostGiftcardRedeemCode (this.extend (request, params)); - // - // { - // "code": "000000", - // "message": "success", - // "data": { - // "referenceNo": "0033002404219823", - // "identityNo": "10316431732801474560" - // }, - // "success": true - // } - // - return response; - } - - async verifyGiftCode (id: string, params = {}) { - /** - * @method - * @name binance#verifyGiftCode - * @description verify gift code - * @see https://binance-docs.github.io/apidocs/spot/en/#verify-binance-gift-card-by-gift-card-number-user_data - * @param {string} id reference number id - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} response from the exchange - */ - const request = { - 'referenceNo': id, - }; - const response = await this.sapiGetGiftcardVerify (this.extend (request, params)); - // - // { - // "code": "000000", - // "message": "success", - // "data": { valid: true }, - // "success": true - // } - // - return response; - } - - async fetchBorrowInterest (code: Str = undefined, symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchBorrowInterest - * @description fetch the interest owed by the user for borrowing currency for margin trading - * @see https://binance-docs.github.io/apidocs/spot/en/#get-interest-history-user_data - * @param {string} code unified currency code - * @param {string} symbol unified market symbol when fetch interest in isolated markets - * @param {int} [since] the earliest time in ms to fetch borrrow interest for - * @param {int} [limit] the maximum number of structures to retrieve - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object[]} a list of [borrow interest structures]{@link https://docs.ccxt.com/#/?id=borrow-interest-structure} - */ - await this.loadMarkets (); - const request = {}; - let market = undefined; - if (code !== undefined) { - const currency = this.currency (code); - request['asset'] = currency['id']; - } - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - request['size'] = limit; - } - if (symbol !== undefined) { // Isolated - market = this.market (symbol); - request['isolatedSymbol'] = market['id']; - } - const response = await this.sapiGetMarginInterestHistory (this.extend (request, params)); - // - // { - // "rows":[ - // { - // "isolatedSymbol": "BNBUSDT", // isolated symbol, will not be returned for crossed margin - // "asset": "BNB", - // "interest": "0.02414667", - // "interestAccuredTime": 1566813600000, - // "interestRate": "0.01600000", - // "principal": "36.22000000", - // "type": "ON_BORROW" - // } - // ], - // "total": 1 - // } - // - const rows = this.safeValue (response, 'rows'); - const interest = this.parseBorrowInterests (rows, market); - return this.filterByCurrencySinceLimit (interest, code, since, limit); - } - - parseBorrowInterest (info, market: Market = undefined) { - const symbol = this.safeString (info, 'isolatedSymbol'); - const timestamp = this.safeNumber (info, 'interestAccuredTime'); - const marginMode = (symbol === undefined) ? 'cross' : 'isolated'; - return { - 'account': (symbol === undefined) ? 'cross' : symbol, - 'symbol': symbol, - 'marginMode': marginMode, - 'currency': this.safeCurrencyCode (this.safeString (info, 'asset')), - 'interest': this.safeNumber (info, 'interest'), - 'interestRate': this.safeNumber (info, 'interestRate'), - 'amountBorrowed': this.safeNumber (info, 'principal'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'info': info, - }; - } - - async repayCrossMargin (code: string, amount, params = {}) { - /** - * @method - * @name binance#repayCrossMargin - * @description repay borrowed margin and interest - * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-repay-margin - * @param {string} code unified currency code of the currency to repay - * @param {float} amount the amount to repay - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'asset': currency['id'], - 'amount': this.currencyToPrecision (code, amount), - 'isIsolated': 'FALSE', - }; - const response = await this.sapiPostMarginRepay (this.extend (request, params)); - // - // { - // "tranId": 108988250265, - // "clientTag":"" - // } - // - return this.parseMarginLoan (response, currency); - } - - async repayIsolatedMargin (symbol: string, code: string, amount, params = {}) { - /** - * @method - * @name binance#repayIsolatedMargin - * @description repay borrowed margin and interest - * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-repay-margin - * @param {string} symbol unified market symbol, required for isolated margin - * @param {string} code unified currency code of the currency to repay - * @param {float} amount the amount to repay - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const market = this.market (symbol); - const request = { - 'asset': currency['id'], - 'amount': this.currencyToPrecision (code, amount), - 'symbol': market['id'], - 'isIsolated': 'TRUE', - }; - const response = await this.sapiPostMarginRepay (this.extend (request, params)); - // - // { - // "tranId": 108988250265, - // "clientTag":"" - // } - // - return this.parseMarginLoan (response, currency); - } - - async borrowCrossMargin (code: string, amount, params = {}) { - /** - * @method - * @name binance#borrowCrossMargin - * @description create a loan to borrow margin - * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-margin - * @param {string} code unified currency code of the currency to borrow - * @param {float} amount the amount to borrow - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const request = { - 'asset': currency['id'], - 'amount': this.currencyToPrecision (code, amount), - 'isIsolated': 'FALSE', - }; - const response = await this.sapiPostMarginLoan (this.extend (request, params)); - // - // { - // "tranId": 108988250265, - // "clientTag":"" - // } - // - return this.parseMarginLoan (response, currency); - } - - async borrowIsolatedMargin (symbol: string, code: string, amount, params = {}) { - /** - * @method - * @name binance#borrowIsolatedMargin - * @description create a loan to borrow margin - * @see https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-margin - * @param {string} symbol unified market symbol, required for isolated margin - * @param {string} code unified currency code of the currency to borrow - * @param {float} amount the amount to borrow - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [margin loan structure]{@link https://docs.ccxt.com/#/?id=margin-loan-structure} - */ - await this.loadMarkets (); - const currency = this.currency (code); - const market = this.market (symbol); - const request = { - 'asset': currency['id'], - 'amount': this.currencyToPrecision (code, amount), - 'symbol': market['id'], - 'isIsolated': 'TRUE', - }; - const response = await this.sapiPostMarginLoan (this.extend (request, params)); - // - // { - // "tranId": 108988250265, - // "clientTag":"" - // } - // - return this.parseMarginLoan (response, currency); - } - - parseMarginLoan (info, currency: Currency = undefined) { - // - // { - // "tranId": 108988250265, - // "clientTag":"" - // } - // - return { - 'id': this.safeInteger (info, 'tranId'), - 'currency': this.safeCurrencyCode (undefined, currency), - 'amount': undefined, - 'symbol': undefined, - 'timestamp': undefined, - 'datetime': undefined, - 'info': info, - }; - } - - async fetchOpenInterestHistory (symbol: string, timeframe = '5m', since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchOpenInterestHistory - * @description Retrieves the open interest history of a currency - * @see https://binance-docs.github.io/apidocs/delivery/en/#open-interest-statistics - * @see https://binance-docs.github.io/apidocs/futures/en/#open-interest-statistics - * @param {string} symbol Unified CCXT market symbol - * @param {string} timeframe "5m","15m","30m","1h","2h","4h","6h","12h", or "1d" - * @param {int} [since] the time(ms) of the earliest record to retrieve as a unix timestamp - * @param {int} [limit] default 30, max 500 - * @param {object} [params] exchange specific parameters - * @param {int} [params.until] the time(ms) of the latest record to retrieve as a unix timestamp - * @returns {object} an array of [open interest structure]{@link https://docs.ccxt.com/#/?id=open-interest-structure} - */ - if (timeframe === '1m') { - throw new BadRequest (this.id + 'fetchOpenInterestHistory cannot use the 1m timeframe'); - } - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchOpenInterestHistory', 'paginate', false); - if (paginate) { - return await this.fetchPaginatedCallDeterministic ('fetchOpenInterestHistory', symbol, since, limit, timeframe, params, 500) as OpenInterest[]; - } - const market = this.market (symbol); - const request = { - 'period': this.safeString (this.timeframes, timeframe, timeframe), - }; - if (limit !== undefined) { - request['limit'] = limit; - } - const symbolKey = market['linear'] ? 'symbol' : 'pair'; - request[symbolKey] = market['id']; - if (market['inverse']) { - request['contractType'] = this.safeString (params, 'contractType', 'CURRENT_QUARTER'); - } - if (since !== undefined) { - request['startTime'] = since; - } - const until = this.safeInteger2 (params, 'until', 'till'); // unified in milliseconds - const endTime = this.safeInteger (params, 'endTime', until); // exchange-specific in milliseconds - params = this.omit (params, [ 'endTime', 'until', 'till' ]); - if (endTime) { - request['endTime'] = endTime; - } else if (since) { - if (limit === undefined) { - limit = 30; // Exchange default - } - const duration = this.parseTimeframe (timeframe); - request['endTime'] = this.sum (since, duration * limit * 1000); - } - let method = 'fapiDataGetOpenInterestHist'; - if (market['inverse']) { - method = 'dapiDataGetOpenInterestHist'; - } - const response = await this[method] (this.extend (request, params)); - // - // [ - // { - // "symbol":"BTCUSDT", - // "sumOpenInterest":"75375.61700000", - // "sumOpenInterestValue":"3248828883.71251440", - // "timestamp":1642179900000 - // }, - // ... - // ] - // - return this.parseOpenInterests (response, market, since, limit); - } - - async fetchOpenInterest (symbol: string, params = {}) { - /** - * @method - * @name binance#fetchOpenInterest - * @description retrieves the open interest of a contract trading pair - * @see https://binance-docs.github.io/apidocs/futures/en/#open-interest - * @see https://binance-docs.github.io/apidocs/delivery/en/#open-interest - * @see https://binance-docs.github.io/apidocs/voptions/en/#open-interest - * @param {string} symbol unified CCXT market symbol - * @param {object} [params] exchange specific parameters - * @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - const request = {}; - if (market['option']) { - request['underlyingAsset'] = market['baseId']; - request['expiration'] = this.yymmdd (market['expiry']); - } else { - request['symbol'] = market['id']; - } - let method = 'fapiPublicGetOpenInterest'; - if (market['option']) { - method = 'eapiPublicGetOpenInterest'; - } else if (market['inverse']) { - method = 'dapiPublicGetOpenInterest'; - } - const response = await this[method] (this.extend (request, params)); - // - // futures (fapi) - // - // { - // "symbol": "ETHUSDT_230331", - // "openInterest": "23581.677", - // "time": 1677356872265 - // } - // - // futures (dapi) - // - // { - // "symbol": "ETHUSD_PERP", - // "pair": "ETHUSD", - // "openInterest": "26542436", - // "contractType": "PERPETUAL", - // "time": 1677360272224 - // } - // - // options (eapi) - // - // [ - // { - // "symbol": "ETH-230225-1625-C", - // "sumOpenInterest": "460.50", - // "sumOpenInterestUsd": "734957.4358092150", - // "timestamp": "1677304860000" - // } - // ] - // - if (market['option']) { - const result = this.parseOpenInterests (response, market); - for (let i = 0; i < result.length; i++) { - const item = result[i]; - if (item['symbol'] === symbol) { - return item; - } - } - } else { - return this.parseOpenInterest (response, market); - } - } - - parseOpenInterest (interest, market: Market = undefined) { - const timestamp = this.safeInteger2 (interest, 'timestamp', 'time'); - const id = this.safeString (interest, 'symbol'); - const amount = this.safeNumber2 (interest, 'sumOpenInterest', 'openInterest'); - const value = this.safeNumber2 (interest, 'sumOpenInterestValue', 'sumOpenInterestUsd'); - // Inverse returns the number of contracts different from the base or quote volume in this case - // compared with https://www.binance.com/en/futures/funding-history/quarterly/4 - return this.safeOpenInterest ({ - 'symbol': this.safeSymbol (id, market, undefined, 'contract'), - 'baseVolume': market['inverse'] ? undefined : amount, // deprecated - 'quoteVolume': value, // deprecated - 'openInterestAmount': amount, - 'openInterestValue': value, - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - 'info': interest, - }, market); - } - - async fetchMyLiquidations (symbol: Str = undefined, since: Int = undefined, limit: Int = undefined, params = {}) { - /** - * @method - * @name binance#fetchMyLiquidations - * @description retrieves the users liquidated positions - * @see https://binance-docs.github.io/apidocs/spot/en/#get-force-liquidation-record-user_data - * @see https://binance-docs.github.io/apidocs/futures/en/#user-39-s-force-orders-user_data - * @see https://binance-docs.github.io/apidocs/delivery/en/#user-39-s-force-orders-user_data - * @param {string} [symbol] unified CCXT market symbol - * @param {int} [since] the earliest time in ms to fetch liquidations for - * @param {int} [limit] the maximum number of liquidation structures to retrieve - * @param {object} [params] exchange specific parameters for the binance api endpoint - * @param {int} [params.until] timestamp in ms of the latest liquidation - * @param {boolean} [params.paginate] *spot only* default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) - * @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure} - */ - await this.loadMarkets (); - let paginate = false; - [ paginate, params ] = this.handleOptionAndParams (params, 'fetchMyLiquidations', 'paginate'); - if (paginate) { - return await this.fetchPaginatedCallIncremental ('fetchMyLiquidations', symbol, since, limit, params, 'current', 100) as Liquidation[]; - } - let market = undefined; - if (symbol !== undefined) { - market = this.market (symbol); - } - let type = undefined; - [ type, params ] = this.handleMarketTypeAndParams ('fetchMyLiquidations', market, params); - let subType = undefined; - [ subType, params ] = this.handleSubTypeAndParams ('fetchMyLiquidations', market, params, 'linear'); - let request = {}; - if (type !== 'spot') { - request['autoCloseType'] = 'LIQUIDATION'; - } - if (market !== undefined) { - const symbolKey = market['spot'] ? 'isolatedSymbol' : 'symbol'; - request[symbolKey] = market['id']; - } - if (since !== undefined) { - request['startTime'] = since; - } - if (limit !== undefined) { - if (type === 'spot') { - request['size'] = limit; - } else { - request['limit'] = limit; - } - } - [ request, params ] = this.handleUntilOption ('endTime', request, params); - let response = undefined; - if (type === 'spot') { - response = await this.sapiGetMarginForceLiquidationRec (this.extend (request, params)); - } else if (subType === 'linear') { - response = await this.fapiPrivateGetForceOrders (this.extend (request, params)); - } else if (subType === 'inverse') { - response = await this.dapiPrivateGetForceOrders (this.extend (request, params)); - } else { - throw new NotSupported (this.id + ' fetchMyLiquidations() does not support ' + market['type'] + ' markets'); - } - // - // margin - // - // { - // "rows": [ - // { - // "avgPrice": "0.00388359", - // "executedQty": "31.39000000", - // "orderId": 180015097, - // "price": "0.00388110", - // "qty": "31.39000000", - // "side": "SELL", - // "symbol": "BNBBTC", - // "timeInForce": "GTC", - // "isIsolated": true, - // "updatedTime": 1558941374745 - // } - // ], - // "total": 1 - // } - // - // linear - // - // [ - // { - // "orderId": 6071832819, - // "symbol": "BTCUSDT", - // "status": "FILLED", - // "clientOrderId": "autoclose-1596107620040000020", - // "price": "10871.09", - // "avgPrice": "10913.21000", - // "origQty": "0.001", - // "executedQty": "0.001", - // "cumQuote": "10.91321", - // "timeInForce": "IOC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "SELL", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "origType": "LIMIT", - // "time": 1596107620044, - // "updateTime": 1596107620087 - // }, - // ] - // - // inverse - // - // [ - // { - // "orderId": 165123080, - // "symbol": "BTCUSD_200925", - // "pair": "BTCUSD", - // "status": "FILLED", - // "clientOrderId": "autoclose-1596542005017000006", - // "price": "11326.9", - // "avgPrice": "11326.9", - // "origQty": "1", - // "executedQty": "1", - // "cumBase": "0.00882854", - // "timeInForce": "IOC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "SELL", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, - // "origType": "LIMIT", - // "time": 1596542005019, - // "updateTime": 1596542005050 - // }, - // ] - // - const liquidations = this.safeValue (response, 'rows', response); - return this.parseLiquidations (liquidations, market, since, limit); - } - - parseLiquidation (liquidation, market: Market = undefined) { - // - // margin - // - // { - // "avgPrice": "0.00388359", - // "executedQty": "31.39000000", - // "orderId": 180015097, - // "price": "0.00388110", - // "qty": "31.39000000", - // "side": "SELL", - // "symbol": "BNBBTC", - // "timeInForce": "GTC", - // "isIsolated": true, - // "updatedTime": 1558941374745 - // } - // - // linear - // - // { - // "orderId": 6071832819, - // "symbol": "BTCUSDT", - // "status": "FILLED", - // "clientOrderId": "autoclose-1596107620040000020", - // "price": "10871.09", - // "avgPrice": "10913.21000", - // "origQty": "0.001", - // "executedQty": "0.001", - // "cumQuote": "10.91321", - // "timeInForce": "IOC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "SELL", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "origType": "LIMIT", - // "time": 1596107620044, - // "updateTime": 1596107620087 - // } - // - // inverse - // - // { - // "orderId": 165123080, - // "symbol": "BTCUSD_200925", - // "pair": "BTCUSD", - // "status": "FILLED", - // "clientOrderId": "autoclose-1596542005017000006", - // "price": "11326.9", - // "avgPrice": "11326.9", - // "origQty": "1", - // "executedQty": "1", - // "cumBase": "0.00882854", - // "timeInForce": "IOC", - // "type": "LIMIT", - // "reduceOnly": false, - // "closePosition": false, - // "side": "SELL", - // "positionSide": "BOTH", - // "stopPrice": "0", - // "workingType": "CONTRACT_PRICE", - // "priceProtect": false, - // "origType": "LIMIT", - // "time": 1596542005019, - // "updateTime": 1596542005050 - // } - // - const marketId = this.safeString (liquidation, 'symbol'); - const timestamp = this.safeInteger2 (liquidation, 'updatedTime', 'updateTime'); - return this.safeLiquidation ({ - 'info': liquidation, - 'symbol': this.safeSymbol (marketId, market), - 'contracts': this.safeNumber (liquidation, 'executedQty'), - 'contractSize': this.safeNumber (market, 'contractSize'), - 'price': this.safeNumber (liquidation, 'avgPrice'), - 'baseValue': this.safeNumber (liquidation, 'cumBase'), - 'quoteValue': this.safeNumber (liquidation, 'cumQuote'), - 'timestamp': timestamp, - 'datetime': this.iso8601 (timestamp), - }); - } - - async fetchGreeks (symbol: string, params = {}): Promise { - /** - * @method - * @name binance#fetchGreeks - * @description fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract - * @see https://binance-docs.github.io/apidocs/voptions/en/#option-mark-price - * @param {string} symbol unified symbol of the market to fetch greeks for - * @param {object} [params] extra parameters specific to the exchange API endpoint - * @returns {object} a [greeks structure]{@link https://docs.ccxt.com/#/?id=greeks-structure} - */ - await this.loadMarkets (); - const market = this.market (symbol); - const request = { - 'symbol': market['id'], - }; - const response = await this.eapiPublicGetMark (this.extend (request, params)); - // - // [ - // { - // "symbol": "BTC-231229-40000-C", - // "markPrice": "2012", - // "bidIV": "0.60236275", - // "askIV": "0.62267244", - // "markIV": "0.6125176", - // "delta": "0.39111646", - // "theta": "-32.13948531", - // "gamma": "0.00004656", - // "vega": "51.70062218", - // "highPriceLimit": "6474", - // "lowPriceLimit": "5" - // } - // ] - // - return this.parseGreeks (response[0], market); - } - - parseGreeks (greeks, market: Market = undefined) { - // - // { - // "symbol": "BTC-231229-40000-C", - // "markPrice": "2012", - // "bidIV": "0.60236275", - // "askIV": "0.62267244", - // "markIV": "0.6125176", - // "delta": "0.39111646", - // "theta": "-32.13948531", - // "gamma": "0.00004656", - // "vega": "51.70062218", - // "highPriceLimit": "6474", - // "lowPriceLimit": "5" - // } - // - const marketId = this.safeString (greeks, 'symbol'); - const symbol = this.safeSymbol (marketId, market); - return { - 'symbol': symbol, - 'timestamp': undefined, - 'datetime': undefined, - 'delta': this.safeNumber (greeks, 'delta'), - 'gamma': this.safeNumber (greeks, 'gamma'), - 'theta': this.safeNumber (greeks, 'theta'), - 'vega': this.safeNumber (greeks, 'vega'), - 'rho': undefined, - 'bidSize': undefined, - 'askSize': undefined, - 'bidImpliedVolatility': this.safeNumber (greeks, 'bidIV'), - 'askImpliedVolatility': this.safeNumber (greeks, 'askIV'), - 'markImpliedVolatility': this.safeNumber (greeks, 'markIV'), - 'bidPrice': undefined, - 'askPrice': undefined, - 'markPrice': this.safeNumber (greeks, 'markPrice'), - 'lastPrice': undefined, - 'underlyingPrice': undefined, - 'info': greeks, - }; + return this.safeBalance (result); } }