package ccxt // 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 type gemini struct { Exchange } func NewGeminiCore() gemini { p := gemini{} setDefaults(&p) return p } func (this *gemini) Describe() interface{} { return this.DeepExtend(this.Exchange.Describe(), map[string]interface{} { "id": "gemini", "name": "Gemini", "countries": []interface{}{"US"}, "rateLimit": 100, "version": "v1", "pro": true, "has": map[string]interface{} { "CORS": nil, "spot": true, "margin": false, "swap": true, "future": false, "option": false, "addMargin": false, "cancelOrder": true, "closeAllPositions": false, "closePosition": false, "createDepositAddress": true, "createMarketOrder": false, "createOrder": true, "createReduceOnlyOrder": false, "fetchBalance": true, "fetchBidsAsks": false, "fetchBorrowRateHistories": false, "fetchBorrowRateHistory": false, "fetchClosedOrders": false, "fetchCrossBorrowRate": false, "fetchCrossBorrowRates": false, "fetchCurrencies": true, "fetchDepositAddress": true, "fetchDepositAddresses": false, "fetchDepositAddressesByNetwork": true, "fetchDepositsWithdrawals": true, "fetchFundingHistory": false, "fetchFundingRate": false, "fetchFundingRateHistory": false, "fetchFundingRates": false, "fetchIndexOHLCV": false, "fetchIsolatedBorrowRate": false, "fetchIsolatedBorrowRates": false, "fetchLeverage": false, "fetchLeverageTiers": false, "fetchMarginMode": false, "fetchMarkets": true, "fetchMarkOHLCV": false, "fetchMyTrades": true, "fetchOHLCV": true, "fetchOpenInterestHistory": false, "fetchOpenOrders": true, "fetchOrder": true, "fetchOrderBook": true, "fetchOrders": false, "fetchPosition": false, "fetchPositionMode": false, "fetchPositions": false, "fetchPositionsRisk": false, "fetchPremiumIndexOHLCV": false, "fetchTicker": true, "fetchTickers": true, "fetchTrades": true, "fetchTradingFee": false, "fetchTradingFees": true, "fetchTransactions": "emulated", "postOnly": true, "reduceMargin": false, "sandbox": true, "setLeverage": false, "setMarginMode": false, "setPositionMode": false, "withdraw": true, }, "urls": map[string]interface{} { "logo": "https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg", "api": map[string]interface{} { "public": "https://api.gemini.com", "private": "https://api.gemini.com", "web": "https://docs.gemini.com", "webExchange": "https://exchange.gemini.com", }, "www": "https://gemini.com/", "doc": []interface{}{"https://docs.gemini.com/rest-api", "https://docs.sandbox.gemini.com"}, "test": map[string]interface{} { "public": "https://api.sandbox.gemini.com", "private": "https://api.sandbox.gemini.com", "web": "https://docs.gemini.com", "webExchange": "https://exchange.gemini.com", }, "fees": []interface{}{"https://gemini.com/api-fee-schedule", "https://gemini.com/trading-fees", "https://gemini.com/transfer-fees"}, }, "api": map[string]interface{} { "webExchange": map[string]interface{} { "get": []interface{}{""}, }, "web": map[string]interface{} { "get": []interface{}{"rest-api"}, }, "public": map[string]interface{} { "get": map[string]interface{} { "v1/symbols": 5, "v1/symbols/details/{symbol}": 5, "v1/staking/rates": 5, "v1/pubticker/{symbol}": 5, "v2/ticker/{symbol}": 5, "v2/candles/{symbol}/{timeframe}": 5, "v1/trades/{symbol}": 5, "v1/auction/{symbol}": 5, "v1/auction/{symbol}/history": 5, "v1/pricefeed": 5, "v1/book/{symbol}": 5, "v1/earn/rates": 5, }, }, "private": map[string]interface{} { "post": map[string]interface{} { "v1/staking/unstake": 1, "v1/staking/stake": 1, "v1/staking/rewards": 1, "v1/staking/history": 1, "v1/order/new": 1, "v1/order/cancel": 1, "v1/wrap/{symbol}": 1, "v1/order/cancel/session": 1, "v1/order/cancel/all": 1, "v1/order/status": 1, "v1/orders": 1, "v1/mytrades": 1, "v1/notionalvolume": 1, "v1/tradevolume": 1, "v1/clearing/new": 1, "v1/clearing/status": 1, "v1/clearing/cancel": 1, "v1/clearing/confirm": 1, "v1/balances": 1, "v1/balances/staking": 1, "v1/notionalbalances/{currency}": 1, "v1/transfers": 1, "v1/addresses/{network}": 1, "v1/deposit/{network}/newAddress": 1, "v1/deposit/{currency}/newAddress": 1, "v1/withdraw/{currency}": 1, "v1/account/transfer/{currency}": 1, "v1/payments/addbank": 1, "v1/payments/methods": 1, "v1/payments/sen/withdraw": 1, "v1/balances/earn": 1, "v1/earn/interest": 1, "v1/earn/history": 1, "v1/approvedAddresses/{network}/request": 1, "v1/approvedAddresses/account/{network}": 1, "v1/approvedAddresses/{network}/remove": 1, "v1/account": 1, "v1/account/create": 1, "v1/account/list": 1, "v1/heartbeat": 1, "v1/roles": 1, }, }, }, "precisionMode": TICK_SIZE, "fees": map[string]interface{} { "trading": map[string]interface{} { "taker": 0.004, "maker": 0.002, }, }, "httpExceptions": map[string]interface{} { "400": BadRequest, "403": PermissionDenied, "404": OrderNotFound, "406": InsufficientFunds, "429": RateLimitExceeded, "500": ExchangeError, "502": ExchangeNotAvailable, "503": OnMaintenance, }, "timeframes": map[string]interface{} { "1m": "1m", "5m": "5m", "15m": "15m", "30m": "30m", "1h": "1hr", "6h": "6hr", "1d": "1day", }, "exceptions": map[string]interface{} { "exact": map[string]interface{} { "AuctionNotOpen": BadRequest, "ClientOrderIdTooLong": BadRequest, "ClientOrderIdMustBeString": BadRequest, "ConflictingOptions": BadRequest, "EndpointMismatch": BadRequest, "EndpointNotFound": BadRequest, "IneligibleTiming": BadRequest, "InsufficientFunds": InsufficientFunds, "InvalidJson": BadRequest, "InvalidNonce": InvalidNonce, "InvalidApiKey": AuthenticationError, "InvalidOrderType": InvalidOrder, "InvalidPrice": InvalidOrder, "InvalidQuantity": InvalidOrder, "InvalidSide": InvalidOrder, "InvalidSignature": AuthenticationError, "InvalidSymbol": BadRequest, "InvalidTimestampInPayload": BadRequest, "Maintenance": OnMaintenance, "MarketNotOpen": InvalidOrder, "MissingApikeyHeader": AuthenticationError, "MissingOrderField": InvalidOrder, "MissingRole": AuthenticationError, "MissingPayloadHeader": AuthenticationError, "MissingSignatureHeader": AuthenticationError, "NoSSL": AuthenticationError, "OptionsMustBeArray": BadRequest, "OrderNotFound": OrderNotFound, "RateLimit": RateLimitExceeded, "System": ExchangeError, "UnsupportedOption": BadRequest, }, "broad": map[string]interface{} { "The Gemini Exchange is currently undergoing maintenance.": OnMaintenance, "We are investigating technical issues with the Gemini Exchange.": ExchangeNotAvailable, "Internal Server Error": ExchangeNotAvailable, }, }, "options": map[string]interface{} { "fetchMarketsMethod": "fetch_markets_from_api", "fetchMarketFromWebRetries": 10, "fetchMarketsFromAPI": map[string]interface{} { "fetchDetailsForAllSymbols": false, "quoteCurrencies": []interface{}{"USDT", "GUSD", "USD", "DAI", "EUR", "GBP", "SGD", "BTC", "ETH", "LTC", "BCH"}, }, "fetchMarkets": map[string]interface{} { "webApiEnable": true, "webApiRetries": 10, }, "fetchUsdtMarkets": []interface{}{"btcusdt", "ethusdt"}, "fetchCurrencies": map[string]interface{} { "webApiEnable": true, "webApiRetries": 5, "webApiMuteFailure": true, }, "fetchTickerMethod": "fetchTickerV1", "networks": map[string]interface{} { "BTC": "bitcoin", "ERC20": "ethereum", "BCH": "bitcoincash", "LTC": "litecoin", "ZEC": "zcash", "FIL": "filecoin", "DOGE": "dogecoin", "XTZ": "tezos", "AVAXX": "avalanche", "SOL": "solana", "ATOM": "cosmos", "DOT": "polkadot", }, "nonce": "milliseconds", "conflictingMarkets": map[string]interface{} { "paxgusd": map[string]interface{} { "base": "PAXG", "quote": "USD", }, }, }, "features": map[string]interface{} { "default": map[string]interface{} { "sandbox": true, "createOrder": map[string]interface{} { "marginMode": false, "triggerPrice": true, "triggerPriceType": nil, "triggerDirection": false, "stopLossPrice": false, "takeProfitPrice": false, "attachedStopLossTakeProfit": nil, "timeInForce": map[string]interface{} { "IOC": true, "FOK": true, "PO": true, "GTD": false, }, "hedged": false, "trailing": false, "leverage": false, "marketBuyByCost": true, "marketBuyRequiresPrice": false, "selfTradePrevention": false, "iceberg": false, }, "createOrders": nil, "fetchMyTrades": map[string]interface{} { "marginMode": false, "limit": 500, "daysBack": nil, "untilDays": nil, "symbolRequired": true, }, "fetchOrder": map[string]interface{} { "marginMode": false, "trigger": false, "trailing": false, "symbolRequired": false, }, "fetchOpenOrders": map[string]interface{} { "marginMode": false, "limit": nil, "trigger": false, "trailing": false, "symbolRequired": false, }, "fetchOrders": nil, "fetchClosedOrders": nil, "fetchOHLCV": map[string]interface{} { "limit": nil, }, }, "spot": map[string]interface{} { "extends": "default", }, "swap": map[string]interface{} { "linear": map[string]interface{} { "extends": "default", }, "inverse": nil, }, "future": map[string]interface{} { "linear": nil, "inverse": nil, }, }, }) } /** * @method * @name gemini#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} [params] extra parameters specific to the endpoint * @returns {object} an associative dictionary of currencies */ func (this *gemini) FetchCurrencies(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes37715 := (<-this.FetchCurrenciesFromWeb(params)) PanicOnError(retRes37715) ch <- retRes37715 return nil }() return ch } /** * @method * @name gemini#fetchCurrenciesFromWeb * @ignore * @description fetches all available currencies on an exchange * @param {object} [params] extra parameters specific to the endpoint * @returns {object} an associative dictionary of currencies */ func (this *gemini) FetchCurrenciesFromWeb(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params data:= (<-this.FetchWebEndpoint("fetchCurrencies", "webExchangeGet", true, "=\"currencyData\">", "")) PanicOnError(data) if IsTrue(IsEqual(data, nil)) { return nil } // // { // "tradingPairs": [ [ 'BTCUSD', 2, 8, '0.00001', 10, true ], ... ], // "currencies": [ // [ "ORCA", "Orca", 204, 6, 0, 6, 8, false, null, "solana" ], // as confirmed, precisions seem to be the 5th index // [ "ATOM", "Cosmos", 44, 6, 0, 6, 8, false, null, "cosmos" ], // [ "ETH", "Ether", 2, 6, 0, 18, 8, false, null, "ethereum" ], // [ "GBP", "Pound Sterling", 22, 2, 2, 2, 2, true, "£", null ], // ... // ], // "networks": [ // [ "solana", "SOL", "Solana" ], // [ "zcash", "ZEC", "Zcash" ], // [ "tezos", "XTZ", "Tezos" ], // [ "cosmos", "ATOM", "Cosmos" ], // [ "ethereum", "ETH", "Ethereum" ], // ... // ] // } // var result interface{} = map[string]interface{} {} AddElementToObject(this.Options, "tradingPairs", this.SafeList(data, "tradingPairs")) var currenciesArray interface{} = this.SafeValue(data, "currencies", []interface{}{}) for i := 0; IsLessThan(i, GetArrayLength(currenciesArray)); i++ { var currency interface{} = GetValue(currenciesArray, i) var id interface{} = this.SafeString(currency, 0) var code interface{} = this.SafeCurrencyCode(id) var typeVar interface{} = Ternary(IsTrue(this.SafeString(currency, 7)), "fiat", "crypto") var precision interface{} = this.ParseNumber(this.ParsePrecision(this.SafeString(currency, 5))) var networks interface{} = map[string]interface{} {} var networkId interface{} = this.SafeString(currency, 9) var networkCode interface{} = nil if IsTrue(!IsEqual(networkId, nil)) { networkCode = this.NetworkIdToCode(networkId) } if IsTrue(!IsEqual(networkCode, nil)) { AddElementToObject(networks, networkCode, map[string]interface{} { "info": currency, "id": networkId, "network": networkCode, "active": nil, "deposit": nil, "withdraw": nil, "fee": nil, "precision": precision, "limits": map[string]interface{} { "deposit": map[string]interface{} { "min": nil, "max": nil, }, "withdraw": map[string]interface{} { "min": nil, "max": nil, }, }, }) } AddElementToObject(result, code, map[string]interface{} { "info": currency, "id": id, "code": code, "name": this.SafeString(currency, 1), "active": nil, "deposit": nil, "withdraw": nil, "fee": nil, "type": typeVar, "precision": precision, "limits": map[string]interface{} { "deposit": map[string]interface{} { "min": nil, "max": nil, }, "withdraw": map[string]interface{} { "min": nil, "max": nil, }, }, "networks": networks, }) } ch <- result return nil }() return ch } /** * @method * @name gemini#fetchMarkets * @description retrieves data on all markets for gemini * @see https://docs.gemini.com/rest-api/#symbols * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ func (this *gemini) FetchMarkets(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params var method interface{} = this.SafeValue(this.Options, "fetchMarketsMethod", "fetch_markets_from_api") if IsTrue(IsEqual(method, "fetch_markets_from_web")) { var promises interface{} = []interface{}{} AppendToArray(&promises,this.FetchMarketsFromWeb(params)) // get usd markets AppendToArray(&promises,this.FetchUSDTMarkets(params)) // get usdt markets promisesResult:= (<-promiseAll(promises)) PanicOnError(promisesResult) ch <- this.ArrayConcat(GetValue(promisesResult, 0), GetValue(promisesResult, 1)) return nil } retRes49415 := (<-this.FetchMarketsFromAPI(params)) PanicOnError(retRes49415) ch <- retRes49415 return nil }() return ch } func (this *gemini) FetchMarketsFromWeb(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params data:= (<-this.FetchWebEndpoint("fetchMarkets", "webGetRestApi", false, "

Symbols and minimums

")) PanicOnError(data) var error interface{} = Add(this.Id, " fetchMarketsFromWeb() the API doc HTML markup has changed, breaking the parser of order limits and precision info for markets.") var tables interface{} = Split(data, "tbody>") var numTables interface{} = GetArrayLength(tables) if IsTrue(IsLessThan(numTables, 2)) { panic(NotSupported(error)) } var rows interface{} = Split(GetValue(tables, 1), "\n\n") // eslint-disable-line quotes var numRows interface{} = GetArrayLength(rows) if IsTrue(IsLessThan(numRows, 2)) { panic(NotSupported(error)) } var result interface{} = []interface{}{} // skip the first element (empty string) for i := 1; IsLessThan(i, numRows); i++ { var row interface{} = GetValue(rows, i) var cells interface{} = Split(row, "\n") // eslint-disable-line quotes var numCells interface{} = GetArrayLength(cells) if IsTrue(IsLessThan(numCells, 5)) { panic(NotSupported(error)) } // [ // 'btcusd', // currency // '0.00001 BTC (1e-5)', // min order size // '0.00000001 BTC (1e-8)', // tick size // '0.01 USD', // quote currency price increment // '' // ] var marketId interface{} = Replace(GetValue(cells, 0), "", "") marketId = Replace(marketId, "*", "") // const base = this.safeCurrencyCode (baseId); var minAmountString interface{} = Replace(GetValue(cells, 1), "", "") var minAmountParts interface{} = Split(minAmountString, " ") var minAmount interface{} = this.SafeNumber(minAmountParts, 0) var amountPrecisionString interface{} = Replace(GetValue(cells, 2), "", "") var amountPrecisionParts interface{} = Split(amountPrecisionString, " ") var idLength interface{} = Subtract(GetArrayLength(marketId), 0) var startingIndex interface{} = Subtract(idLength, 3) var pricePrecisionString interface{} = Replace(GetValue(cells, 3), "", "") var pricePrecisionParts interface{} = Split(pricePrecisionString, " ") var quoteId interface{} = this.SafeStringLower(pricePrecisionParts, 1, Slice(marketId, startingIndex, idLength)) var baseId interface{} = this.SafeStringLower(amountPrecisionParts, 1, Replace(marketId, quoteId, "")) var base interface{} = this.SafeCurrencyCode(baseId) var quote interface{} = this.SafeCurrencyCode(quoteId) AppendToArray(&result,map[string]interface{} { "id": marketId, "symbol": Add(Add(base, "/"), quote), "base": base, "quote": quote, "settle": nil, "baseId": baseId, "quoteId": quoteId, "settleId": nil, "type": "spot", "spot": true, "margin": false, "swap": false, "future": false, "option": false, "active": nil, "contract": false, "linear": nil, "inverse": nil, "contractSize": nil, "expiry": nil, "expiryDatetime": nil, "strike": nil, "optionType": nil, "precision": map[string]interface{} { "amount": this.SafeNumber(amountPrecisionParts, 0), "price": this.SafeNumber(pricePrecisionParts, 0), }, "limits": map[string]interface{} { "leverage": map[string]interface{} { "min": nil, "max": nil, }, "amount": map[string]interface{} { "min": minAmount, "max": nil, }, "price": map[string]interface{} { "min": nil, "max": nil, }, "cost": map[string]interface{} { "min": nil, "max": nil, }, }, "created": nil, "info": row, }) } ch <- result return nil }() return ch } func (this *gemini) ParseMarketActive(status interface{}) interface{} { var statuses interface{} = map[string]interface{} { "open": true, "closed": false, "cancel_only": true, "post_only": true, "limit_only": true, } if IsTrue(IsEqual(status, nil)) { return true // as defaulted below } return this.SafeBool(statuses, status, true) } func (this *gemini) FetchUSDTMarkets(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) // these markets can't be scrapped and fetchMarketsFrom api does an extra call // to load market ids which we don't need here params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params if IsTrue(InOp(this.Urls, "test")) { ch <- []interface{}{} // sandbox does not have usdt markets return nil } var fetchUsdtMarkets interface{} = this.SafeValue(this.Options, "fetchUsdtMarkets", []interface{}{}) var result interface{} = []interface{}{} for i := 0; IsLessThan(i, GetArrayLength(fetchUsdtMarkets)); i++ { var marketId interface{} = GetValue(fetchUsdtMarkets, i) var request interface{} = map[string]interface{} { "symbol": marketId, } // don't use Promise.all here, for some reason the exchange can't handle it and crashes rawResponse:= (<-this.PublicGetV1SymbolsDetailsSymbol(this.Extend(request, params))) PanicOnError(rawResponse) AppendToArray(&result,this.ParseMarket(rawResponse)) } ch <- result return nil }() return ch } func (this *gemini) FetchMarketsFromAPI(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params marketIdsRaw:= (<-this.PublicGetV1Symbols(params)) PanicOnError(marketIdsRaw) // // [ // "btcusd", // "linkusd", // ... // ] // var result interface{} = []interface{}{} var options interface{} = this.SafeDict(this.Options, "fetchMarketsFromAPI", map[string]interface{} {}) var bugSymbol interface{} = "efilfil" // we skip this inexistent test symbol, which bugs other functions var marketIds interface{} = []interface{}{} for i := 0; IsLessThan(i, GetArrayLength(marketIdsRaw)); i++ { if IsTrue(!IsEqual(GetValue(marketIdsRaw, i), bugSymbol)) { AppendToArray(&marketIds,GetValue(marketIdsRaw, i)) } } if IsTrue(this.SafeBool(options, "fetchDetailsForAllSymbols", false)) { var promises interface{} = []interface{}{} for i := 0; IsLessThan(i, GetArrayLength(marketIds)); i++ { var marketId interface{} = GetValue(marketIds, i) var request interface{} = map[string]interface{} { "symbol": marketId, } AppendToArray(&promises,this.PublicGetV1SymbolsDetailsSymbol(this.Extend(request, params))) } responses:= (<-promiseAll(promises)) PanicOnError(responses) for i := 0; IsLessThan(i, GetArrayLength(responses)); i++ { AppendToArray(&result,this.ParseMarket(GetValue(responses, i))) } } else { // use trading-pairs info, if it was fetched var tradingPairs interface{} = this.SafeList(this.Options, "tradingPairs") if IsTrue(!IsEqual(tradingPairs, nil)) { var indexedTradingPairs interface{} = this.IndexBy(tradingPairs, 0) for i := 0; IsLessThan(i, GetArrayLength(marketIds)); i++ { var marketId interface{} = GetValue(marketIds, i) var tradingPair interface{} = this.SafeList(indexedTradingPairs, ToUpper(marketId)) if IsTrue(!IsEqual(tradingPair, nil)) { AppendToArray(&result,this.ParseMarket(tradingPair)) } } } else { for i := 0; IsLessThan(i, GetArrayLength(marketIds)); i++ { AppendToArray(&result,this.ParseMarket(GetValue(marketIds, i))) } } } ch <- result return nil }() return ch } func (this *gemini) ParseMarket(response interface{}) interface{} { // // response might be: // // btcusd // // or // // [ // 'BTCUSD', // symbol // 2, // priceTickDecimalPlaces // 8, // quantityTickDecimalPlaces // '0.00001', // quantityMinimum // 10, // quantityRoundDecimalPlaces // true // minimumsAreInclusive // ], // // or // // { // "symbol": "BTCUSD", // perpetuals have 'PERP' suffix, i.e. DOGEUSDPERP // "base_currency": "BTC", // "quote_currency": "USD", // "tick_size": 1E-8, // "quote_increment": 0.01, // "min_order_size": "0.00001", // "status": "open", // "wrap_enabled": false // "product_type": "swap", // only in perps // "contract_type": "linear", // only in perps // "contract_price_currency": "GUSD" // only in perps // } // var marketId interface{} = nil var baseId interface{} = nil var quoteId interface{} = nil var settleId interface{} = nil var tickSize interface{} = nil var amountPrecision interface{} = nil var minSize interface{} = nil var status interface{} = nil var swap interface{} = false var contractSize interface{} = nil var linear interface{} = nil var inverse interface{} = nil var isString interface{} = (IsString(response)) var isArray interface{} = (IsArray(response)) if IsTrue(!IsTrue(isString) && !IsTrue(isArray)) { marketId = this.SafeStringLower(response, "symbol") amountPrecision = this.SafeNumber(response, "tick_size") // right, exchange has an imperfect naming and this turns out to be an amount-precision tickSize = this.SafeNumber(response, "quote_increment") // this is tick-size actually minSize = this.SafeNumber(response, "min_order_size") status = this.ParseMarketActive(this.SafeString(response, "status")) baseId = this.SafeString(response, "base_currency") quoteId = this.SafeString(response, "quote_currency") settleId = this.SafeString(response, "contract_price_currency") } else { // if no detailed API was called, then parse either string or array if IsTrue(isString) { marketId = response } else { marketId = this.SafeStringLower(response, 0) tickSize = this.ParseNumber(this.ParsePrecision(this.SafeString(response, 1))) // priceTickDecimalPlaces amountPrecision = this.ParseNumber(this.ParsePrecision(this.SafeString(response, 2))) // quantityTickDecimalPlaces minSize = this.SafeNumber(response, 3) // quantityMinimum } var marketIdUpper interface{} = ToUpper(marketId) var isPerp interface{} = (IsGreaterThanOrEqual(GetIndexOf(marketIdUpper, "PERP"), 0)) var marketIdWithoutPerp interface{} = Replace(marketIdUpper, "PERP", "") var conflictingMarkets interface{} = this.SafeDict(this.Options, "conflictingMarkets", map[string]interface{} {}) var lowerCaseId interface{} = ToLower(marketIdWithoutPerp) if IsTrue(InOp(conflictingMarkets, lowerCaseId)) { var conflictingMarket interface{} = GetValue(conflictingMarkets, lowerCaseId) baseId = GetValue(conflictingMarket, "base") quoteId = GetValue(conflictingMarket, "quote") if IsTrue(isPerp) { settleId = GetValue(conflictingMarket, "quote") } } else { var quoteCurrencies interface{} = this.HandleOption("fetchMarketsFromAPI", "quoteCurrencies", []interface{}{}) for i := 0; IsLessThan(i, GetArrayLength(quoteCurrencies)); i++ { var quoteCurrency interface{} = GetValue(quoteCurrencies, i) if IsTrue(EndsWith(marketIdWithoutPerp, quoteCurrency)) { var quoteLength interface{} = this.ParseToInt(Multiply(OpNeg(1), GetArrayLength(quoteCurrency))) baseId = Slice(marketIdWithoutPerp, 0, quoteLength) quoteId = quoteCurrency if IsTrue(isPerp) { settleId = quoteCurrency // always same } break } } } } var base interface{} = this.SafeCurrencyCode(baseId) var quote interface{} = this.SafeCurrencyCode(quoteId) var settle interface{} = this.SafeCurrencyCode(settleId) var symbol interface{} = Add(Add(base, "/"), quote) if IsTrue(!IsEqual(settleId, nil)) { symbol = Add(Add(symbol, ":"), settle) swap = true contractSize = tickSize // always same linear = true // always linear inverse = false } var typeVar interface{} = Ternary(IsTrue(swap), "swap", "spot") return map[string]interface{} { "id": marketId, "symbol": symbol, "base": base, "quote": quote, "settle": settle, "baseId": baseId, "quoteId": quoteId, "settleId": settleId, "type": typeVar, "spot": !IsTrue(swap), "margin": false, "swap": swap, "future": false, "option": false, "active": status, "contract": swap, "linear": linear, "inverse": inverse, "contractSize": contractSize, "expiry": nil, "expiryDatetime": nil, "strike": nil, "optionType": nil, "precision": map[string]interface{} { "price": tickSize, "amount": amountPrecision, }, "limits": map[string]interface{} { "leverage": map[string]interface{} { "min": nil, "max": nil, }, "amount": map[string]interface{} { "min": minSize, "max": nil, }, "price": map[string]interface{} { "min": nil, "max": nil, }, "cost": map[string]interface{} { "min": nil, "max": nil, }, }, "created": nil, "info": response, } } /** * @method * @name gemini#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://docs.gemini.com/rest-api/#current-order-book * @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 */ func (this *gemini) FetchOrderBook(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) limit := GetArg(optionalArgs, 0, nil) _ = limit params := GetArg(optionalArgs, 1, map[string]interface{} {}) _ = params retRes8618 := (<-this.LoadMarkets()) PanicOnError(retRes8618) var market interface{} = this.Market(symbol) var request interface{} = map[string]interface{} { "symbol": GetValue(market, "id"), } if IsTrue(!IsEqual(limit, nil)) { AddElementToObject(request, "limit_bids", limit) AddElementToObject(request, "limit_asks", limit) } response:= (<-this.PublicGetV1BookSymbol(this.Extend(request, params))) PanicOnError(response) ch <- this.ParseOrderBook(response, GetValue(market, "symbol"), nil, "bids", "asks", "price", "amount") return nil }() return ch } func (this *gemini) FetchTickerV1(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes8758 := (<-this.LoadMarkets()) PanicOnError(retRes8758) var market interface{} = this.Market(symbol) var request interface{} = map[string]interface{} { "symbol": GetValue(market, "id"), } response:= (<-this.PublicGetV1PubtickerSymbol(this.Extend(request, params))) PanicOnError(response) // // { // "bid":"9117.95", // "ask":"9117.96", // "volume":{ // "BTC":"1615.46861748", // "USD":"14727307.57545006088", // "timestamp":1594982700000 // }, // "last":"9115.23" // } // ch <- this.ParseTicker(response, market) return nil }() return ch } func (this *gemini) FetchTickerV2(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes8978 := (<-this.LoadMarkets()) PanicOnError(retRes8978) var market interface{} = this.Market(symbol) var request interface{} = map[string]interface{} { "symbol": GetValue(market, "id"), } response:= (<-this.PublicGetV2TickerSymbol(this.Extend(request, params))) PanicOnError(response) // // { // "symbol":"BTCUSD", // "open":"9080.58", // "high":"9184.53", // "low":"9063.56", // "close":"9116.08", // // Hourly prices descending for past 24 hours // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"], // "bid":"9115.86", // "ask":"9115.87" // } // ch <- this.ParseTicker(response, market) return nil }() return ch } func (this *gemini) FetchTickerV1AndV2(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params var tickerPromiseA interface{} = this.FetchTickerV1(symbol, params) var tickerPromiseB interface{} = this.FetchTickerV2(symbol, params) tickerAtickerBVariable := (<-promiseAll([]interface{}{tickerPromiseA, tickerPromiseB})); tickerA := GetValue(tickerAtickerBVariable,0); tickerB := GetValue(tickerAtickerBVariable,1) ch <- this.DeepExtend(tickerA, map[string]interface{} { "open": GetValue(tickerB, "open"), "high": GetValue(tickerB, "high"), "low": GetValue(tickerB, "low"), "change": GetValue(tickerB, "change"), "percentage": GetValue(tickerB, "percentage"), "average": GetValue(tickerB, "average"), "info": GetValue(tickerB, "info"), }) return nil }() return ch } /** * @method * @name gemini#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @see https://docs.gemini.com/rest-api/#ticker * @see https://docs.gemini.com/rest-api/#ticker-v2 * @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 {object} [params.fetchTickerMethod] 'fetchTickerV2', 'fetchTickerV1' or 'fetchTickerV1AndV2' - 'fetchTickerV1' for original ccxt.gemini.fetchTicker - 'fetchTickerV1AndV2' for 2 api calls to get the result of both fetchTicker methods - default = 'fetchTickerV1' * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ func (this *gemini) FetchTicker(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params var method interface{} = this.SafeValue(this.Options, "fetchTickerMethod", "fetchTickerV1") if IsTrue(IsEqual(method, "fetchTickerV1")) { retRes94819 := (<-this.FetchTickerV1(symbol, params)) PanicOnError(retRes94819) ch <- retRes94819 return nil } if IsTrue(IsEqual(method, "fetchTickerV2")) { retRes95119 := (<-this.FetchTickerV2(symbol, params)) PanicOnError(retRes95119) ch <- retRes95119 return nil } retRes95315 := (<-this.FetchTickerV1AndV2(symbol, params)) PanicOnError(retRes95315) ch <- retRes95315 return nil }() return ch } func (this *gemini) ParseTicker(ticker interface{}, optionalArgs ...interface{}) interface{} { // // fetchTickers // // { // "pair": "BATUSD", // "price": "0.20687", // "percentChange24h": "0.0146" // } // // fetchTickerV1 // // { // "bid":"9117.95", // "ask":"9117.96", // "volume":{ // "BTC":"1615.46861748", // "USD":"14727307.57545006088", // "timestamp":1594982700000 // }, // "last":"9115.23" // } // // fetchTickerV2 // // { // "symbol":"BTCUSD", // "open":"9080.58", // "high":"9184.53", // "low":"9063.56", // "close":"9116.08", // // Hourly prices descending for past 24 hours // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"], // "bid":"9115.86", // "ask":"9115.87" // } // market := GetArg(optionalArgs, 0, nil) _ = market var volume interface{} = this.SafeValue(ticker, "volume", map[string]interface{} {}) var timestamp interface{} = this.SafeInteger(volume, "timestamp") var symbol interface{} = nil var marketId interface{} = this.SafeStringLower(ticker, "pair") market = this.SafeMarket(marketId, market) var baseId interface{} = nil var quoteId interface{} = nil var base interface{} = nil var quote interface{} = nil if IsTrue(IsTrue((!IsEqual(marketId, nil))) && IsTrue((IsEqual(market, nil)))) { var idLength interface{} = Subtract(GetLength(marketId), 0) if IsTrue(IsEqual(idLength, 7)) { baseId = Slice(marketId, 0, 4) quoteId = Slice(marketId, 4, 7) } else { baseId = Slice(marketId, 0, 3) quoteId = Slice(marketId, 3, 6) } base = this.SafeCurrencyCode(baseId) quote = this.SafeCurrencyCode(quoteId) symbol = Add(Add(base, "/"), quote) } if IsTrue(IsTrue((IsEqual(symbol, nil))) && IsTrue((!IsEqual(market, nil)))) { symbol = GetValue(market, "symbol") baseId = this.SafeStringUpper(market, "baseId") quoteId = this.SafeStringUpper(market, "quoteId") } var price interface{} = this.SafeString(ticker, "price") var last interface{} = this.SafeString2(ticker, "last", "close", price) var percentage interface{} = this.SafeString(ticker, "percentChange24h") var open interface{} = this.SafeString(ticker, "open") var baseVolume interface{} = this.SafeString(volume, baseId) var quoteVolume interface{} = this.SafeString(volume, quoteId) return this.SafeTicker(map[string]interface{} { "symbol": symbol, "timestamp": timestamp, "datetime": this.Iso8601(timestamp), "high": this.SafeString(ticker, "high"), "low": this.SafeString(ticker, "low"), "bid": this.SafeString(ticker, "bid"), "bidVolume": nil, "ask": this.SafeString(ticker, "ask"), "askVolume": nil, "vwap": nil, "open": open, "close": last, "last": last, "previousClose": nil, "change": nil, "percentage": percentage, "average": nil, "baseVolume": baseVolume, "quoteVolume": quoteVolume, "info": ticker, }, market) } /** * @method * @name gemini#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://docs.gemini.com/rest-api/#price-feed * @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} */ func (this *gemini) FetchTickers(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) symbols := GetArg(optionalArgs, 0, nil) _ = symbols params := GetArg(optionalArgs, 1, map[string]interface{} {}) _ = params retRes10608 := (<-this.LoadMarkets()) PanicOnError(retRes10608) response:= (<-this.PublicGetV1Pricefeed(params)) PanicOnError(response) // // [ // { // "pair": "BATUSD", // "price": "0.20687", // "percentChange24h": "0.0146" // }, // { // "pair": "LINKETH", // "price": "0.018", // "percentChange24h": "0.0000" // }, // ] // ch <- this.ParseTickers(response, symbols) return nil }() return ch } func (this *gemini) ParseTrade(trade interface{}, optionalArgs ...interface{}) interface{} { // // public fetchTrades // // { // "timestamp":1601617445, // "timestampms":1601617445144, // "tid":14122489752, // "price":"0.46476", // "amount":"28.407209", // "exchange":"gemini", // "type":"buy" // } // // private fetchTrades // // { // "price":"3900.00", // "amount":"0.00996", // "timestamp":1638891173, // "timestampms":1638891173518, // "type":"Sell", // "aggressor":false, // "fee_currency":"EUR", // "fee_amount":"0.00", // "tid":73621746145, // "order_id":"73621746059", // "exchange":"gemini", // "is_auction_fill":false, // "is_clearing_fill":false, // "symbol":"ETHEUR", // "client_order_id":"1638891171610" // } // market := GetArg(optionalArgs, 0, nil) _ = market var timestamp interface{} = this.SafeInteger(trade, "timestampms") var id interface{} = this.SafeString(trade, "tid") var orderId interface{} = this.SafeString(trade, "order_id") var feeCurrencyId interface{} = this.SafeString(trade, "fee_currency") var feeCurrencyCode interface{} = this.SafeCurrencyCode(feeCurrencyId) var fee interface{} = map[string]interface{} { "cost": this.SafeString(trade, "fee_amount"), "currency": feeCurrencyCode, } var priceString interface{} = this.SafeString(trade, "price") var amountString interface{} = this.SafeString(trade, "amount") var side interface{} = this.SafeStringLower(trade, "type") var symbol interface{} = this.SafeSymbol(nil, market) return this.SafeTrade(map[string]interface{} { "id": id, "order": orderId, "info": trade, "timestamp": timestamp, "datetime": this.Iso8601(timestamp), "symbol": symbol, "type": nil, "side": side, "takerOrMaker": nil, "price": priceString, "cost": nil, "amount": amountString, "fee": fee, }, market) } /** * @method * @name gemini#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://docs.gemini.com/rest-api/#trade-history * @param {string} symbol unified symbol of the market to fetch trades for * @param {int} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount of trades 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} */ func (this *gemini) FetchTrades(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) since := GetArg(optionalArgs, 0, nil) _ = since limit := GetArg(optionalArgs, 1, nil) _ = limit params := GetArg(optionalArgs, 2, map[string]interface{} {}) _ = params retRes11558 := (<-this.LoadMarkets()) PanicOnError(retRes11558) var market interface{} = this.Market(symbol) var request interface{} = map[string]interface{} { "symbol": GetValue(market, "id"), } if IsTrue(!IsEqual(limit, nil)) { AddElementToObject(request, "limit_trades", mathMin(limit, 500)) } if IsTrue(!IsEqual(since, nil)) { AddElementToObject(request, "timestamp", since) } response:= (<-this.PublicGetV1TradesSymbol(this.Extend(request, params))) PanicOnError(response) // // [ // { // "timestamp":1601617445, // "timestampms":1601617445144, // "tid":14122489752, // "price":"0.46476", // "amount":"28.407209", // "exchange":"gemini", // "type":"buy" // }, // ] // ch <- this.ParseTrades(response, market, since, limit) return nil }() return ch } func (this *gemini) ParseBalance(response interface{}) interface{} { var result interface{} = map[string]interface{} { "info": response, } for i := 0; IsLessThan(i, GetArrayLength(response)); i++ { var balance interface{} = GetValue(response, i) var currencyId interface{} = this.SafeString(balance, "currency") var code interface{} = this.SafeCurrencyCode(currencyId) var account interface{} = this.Account() AddElementToObject(account, "free", this.SafeString(balance, "available")) AddElementToObject(account, "total", this.SafeString(balance, "amount")) AddElementToObject(result, code, account) } return this.SafeBalance(result) } /** * @method * @name gemini#fetchTradingFees * @description fetch the trading fees for multiple markets * @see https://docs.gemini.com/rest-api/#get-notional-volume * @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 */ func (this *gemini) FetchTradingFees(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes12068 := (<-this.LoadMarkets()) PanicOnError(retRes12068) response:= (<-this.PrivatePostV1Notionalvolume(params)) PanicOnError(response) // // { // "web_maker_fee_bps": 25, // "web_taker_fee_bps": 35, // "web_auction_fee_bps": 25, // "api_maker_fee_bps": 10, // "api_taker_fee_bps": 35, // "api_auction_fee_bps": 20, // "fix_maker_fee_bps": 10, // "fix_taker_fee_bps": 35, // "fix_auction_fee_bps": 20, // "block_maker_fee_bps": 0, // "block_taker_fee_bps": 50, // "notional_30d_volume": 150.00, // "last_updated_ms": 1551371446000, // "date": "2019-02-28", // "notional_1d_volume": [ // { // "date": "2019-02-22", // "notional_volume": 75.00 // }, // { // "date": "2019-02-14", // "notional_volume": 75.00 // } // ] // } // var makerBps interface{} = this.SafeString(response, "api_maker_fee_bps") var takerBps interface{} = this.SafeString(response, "api_taker_fee_bps") var makerString interface{} = Precise.StringDiv(makerBps, "10000") var takerString interface{} = Precise.StringDiv(takerBps, "10000") var maker interface{} = this.ParseNumber(makerString) var taker interface{} = this.ParseNumber(takerString) var result interface{} = map[string]interface{} {} for i := 0; IsLessThan(i, GetArrayLength(this.Symbols)); i++ { var symbol interface{} = GetValue(this.Symbols, i) AddElementToObject(result, symbol, map[string]interface{} { "info": response, "symbol": symbol, "maker": maker, "taker": taker, "percentage": true, "tierBased": true, }) } ch <- result return nil }() return ch } /** * @method * @name gemini#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://docs.gemini.com/rest-api/#get-available-balances * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ func (this *gemini) FetchBalance(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes12668 := (<-this.LoadMarkets()) PanicOnError(retRes12668) response:= (<-this.PrivatePostV1Balances(params)) PanicOnError(response) ch <- this.ParseBalance(response) return nil }() return ch } func (this *gemini) ParseOrder(order interface{}, optionalArgs ...interface{}) interface{} { // // createOrder (private) // // { // "order_id":"106027397702", // "id":"106027397702", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"2877.48", // "side":"sell", // "type":"exchange limit", // "timestamp":"1650398122", // "timestampms":1650398122308, // "is_live":false, // "is_cancelled":false, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0.014434", // "client_order_id":"1650398121695", // "options":[], // "price":"2800.00", // "original_amount":"0.014434", // "remaining_amount":"0" // } // // fetchOrder (private) // // { // "order_id":"106028543717", // "id":"106028543717", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"0.00", // "side":"buy", // "type":"exchange limit", // "timestamp":"1650398446", // "timestampms":1650398446375, // "is_live":true, // "is_cancelled":false, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0", // "client_order_id":"1650398445709", // "options":[], // "price":"2000.00", // "original_amount":"0.01", // "remaining_amount":"0.01" // } // // fetchOpenOrders (private) // // { // "order_id":"106028543717", // "id":"106028543717", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"0.00", // "side":"buy", // "type":"exchange limit", // "timestamp":"1650398446", // "timestampms":1650398446375, // "is_live":true, // "is_cancelled":false, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0", // "client_order_id":"1650398445709", // "options":[], // "price":"2000.00", // "original_amount":"0.01", // "remaining_amount":"0.01" // } // // cancelOrder (private) // // { // "order_id":"106028543717", // "id":"106028543717", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"0.00", // "side":"buy", // "type":"exchange limit", // "timestamp":"1650398446", // "timestampms":1650398446375, // "is_live":false, // "is_cancelled":true, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0", // "client_order_id":"1650398445709", // "reason":"Requested", // "options":[], // "price":"2000.00", // "original_amount":"0.01", // "remaining_amount":"0.01" // } // market := GetArg(optionalArgs, 0, nil) _ = market var timestamp interface{} = this.SafeInteger(order, "timestampms") var amount interface{} = this.SafeString(order, "original_amount") var remaining interface{} = this.SafeString(order, "remaining_amount") var filled interface{} = this.SafeString(order, "executed_amount") var status interface{} = "closed" if IsTrue(GetValue(order, "is_live")) { status = "open" } if IsTrue(GetValue(order, "is_cancelled")) { status = "canceled" } var price interface{} = this.SafeString(order, "price") var average interface{} = this.SafeString(order, "avg_execution_price") var typeVar interface{} = this.SafeString(order, "type") if IsTrue(IsEqual(typeVar, "exchange limit")) { typeVar = "limit" } else if IsTrue(IsTrue(IsEqual(typeVar, "market buy")) || IsTrue(IsEqual(typeVar, "market sell"))) { typeVar = "market" } else { typeVar = GetValue(order, "type") } var fee interface{} = nil var marketId interface{} = this.SafeString(order, "symbol") var symbol interface{} = this.SafeSymbol(marketId, market) var id interface{} = this.SafeString(order, "order_id") var side interface{} = this.SafeStringLower(order, "side") var clientOrderId interface{} = this.SafeString(order, "client_order_id") var optionsArray interface{} = this.SafeValue(order, "options", []interface{}{}) var option interface{} = this.SafeString(optionsArray, 0) var timeInForce interface{} = "GTC" var postOnly interface{} = false if IsTrue(!IsEqual(option, nil)) { if IsTrue(IsEqual(option, "immediate-or-cancel")) { timeInForce = "IOC" } else if IsTrue(IsEqual(option, "fill-or-kill")) { timeInForce = "FOK" } else if IsTrue(IsEqual(option, "maker-or-cancel")) { timeInForce = "PO" postOnly = true } } return this.SafeOrder(map[string]interface{} { "id": id, "clientOrderId": clientOrderId, "info": order, "timestamp": timestamp, "datetime": this.Iso8601(timestamp), "lastTradeTimestamp": nil, "status": status, "symbol": symbol, "type": typeVar, "timeInForce": timeInForce, "postOnly": postOnly, "side": side, "price": price, "triggerPrice": nil, "average": average, "cost": nil, "amount": amount, "filled": filled, "remaining": remaining, "fee": fee, "trades": nil, }, market) } /** * @method * @name gemini#fetchOrder * @description fetches information on an order made by the user * @see https://docs.gemini.com/rest-api/#order-status * @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} */ func (this *gemini) FetchOrder(id interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) symbol := GetArg(optionalArgs, 0, nil) _ = symbol params := GetArg(optionalArgs, 1, map[string]interface{} {}) _ = params retRes14478 := (<-this.LoadMarkets()) PanicOnError(retRes14478) var request interface{} = map[string]interface{} { "order_id": id, } response:= (<-this.PrivatePostV1OrderStatus(this.Extend(request, params))) PanicOnError(response) // // { // "order_id":"106028543717", // "id":"106028543717", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"0.00", // "side":"buy", // "type":"exchange limit", // "timestamp":"1650398446", // "timestampms":1650398446375, // "is_live":true, // "is_cancelled":false, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0", // "client_order_id":"1650398445709", // "options":[], // "price":"2000.00", // "original_amount":"0.01", // "remaining_amount":"0.01" // } // ch <- this.ParseOrder(response) return nil }() return ch } /** * @method * @name gemini#fetchOpenOrders * @description fetch all unfilled currently open orders * @see https://docs.gemini.com/rest-api/#get-active-orders * @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 * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ func (this *gemini) FetchOpenOrders(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) symbol := GetArg(optionalArgs, 0, nil) _ = symbol since := GetArg(optionalArgs, 1, nil) _ = since limit := GetArg(optionalArgs, 2, nil) _ = limit params := GetArg(optionalArgs, 3, map[string]interface{} {}) _ = params retRes14908 := (<-this.LoadMarkets()) PanicOnError(retRes14908) response:= (<-this.PrivatePostV1Orders(params)) PanicOnError(response) // // [ // { // "order_id":"106028543717", // "id":"106028543717", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"0.00", // "side":"buy", // "type":"exchange limit", // "timestamp":"1650398446", // "timestampms":1650398446375, // "is_live":true, // "is_cancelled":false, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0", // "client_order_id":"1650398445709", // "options":[], // "price":"2000.00", // "original_amount":"0.01", // "remaining_amount":"0.01" // } // ] // var market interface{} = nil if IsTrue(!IsEqual(symbol, nil)) { market = this.Market(symbol) // throws on non-existent symbol } ch <- this.ParseOrders(response, market, since, limit) return nil }() return ch } /** * @method * @name gemini#createOrder * @description create a trade order * @see https://docs.gemini.com/rest-api/#new-order * @param {string} symbol unified symbol of the market to create an order in * @param {string} type must be '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 fulfilled, in units of the quote 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} */ func (this *gemini) CreateOrder(symbol interface{}, typeVar interface{}, side interface{}, amount interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) price := GetArg(optionalArgs, 0, nil) _ = price params := GetArg(optionalArgs, 1, map[string]interface{} {}) _ = params retRes15388 := (<-this.LoadMarkets()) PanicOnError(retRes15388) if IsTrue(!IsEqual(typeVar, "limit")) { panic(ExchangeError(Add(this.Id, " createOrder() allows limit orders only"))) } var clientOrderId interface{} = this.SafeString2(params, "clientOrderId", "client_order_id") params = this.Omit(params, []interface{}{"clientOrderId", "client_order_id"}) if IsTrue(IsEqual(clientOrderId, nil)) { clientOrderId = ToString(this.Milliseconds()) } var market interface{} = this.Market(symbol) var amountString interface{} = this.AmountToPrecision(symbol, amount) var priceString interface{} = this.PriceToPrecision(symbol, price) var request interface{} = map[string]interface{} { "client_order_id": clientOrderId, "symbol": GetValue(market, "id"), "amount": amountString, "price": priceString, "side": side, "type": "exchange limit", } typeVar = this.SafeString(params, "type", typeVar) params = this.Omit(params, "type") var triggerPrice interface{} = this.SafeStringN(params, []interface{}{"triggerPrice", "stop_price", "stopPrice"}) params = this.Omit(params, []interface{}{"triggerPrice", "stop_price", "stopPrice", "type"}) if IsTrue(IsEqual(typeVar, "stopLimit")) { panic(ArgumentsRequired(Add(Add(Add(this.Id, " createOrder() requires a triggerPrice parameter or a stop_price parameter for "), typeVar), " orders"))) } if IsTrue(!IsEqual(triggerPrice, nil)) { AddElementToObject(request, "stop_price", this.PriceToPrecision(symbol, triggerPrice)) AddElementToObject(request, "type", "exchange stop limit") } else { // No options can be applied to stop-limit orders at this time. var timeInForce interface{} = this.SafeString(params, "timeInForce") params = this.Omit(params, "timeInForce") if IsTrue(!IsEqual(timeInForce, nil)) { if IsTrue(IsTrue((IsEqual(timeInForce, "IOC"))) || IsTrue((IsEqual(timeInForce, "immediate-or-cancel")))) { AddElementToObject(request, "options", []interface{}{"immediate-or-cancel"}) } else if IsTrue(IsTrue((IsEqual(timeInForce, "FOK"))) || IsTrue((IsEqual(timeInForce, "fill-or-kill")))) { AddElementToObject(request, "options", []interface{}{"fill-or-kill"}) } else if IsTrue(IsEqual(timeInForce, "PO")) { AddElementToObject(request, "options", []interface{}{"maker-or-cancel"}) } } var postOnly interface{} = this.SafeBool(params, "postOnly", false) params = this.Omit(params, "postOnly") if IsTrue(postOnly) { AddElementToObject(request, "options", []interface{}{"maker-or-cancel"}) } // allowing override for auction-only and indication-of-interest order options var options interface{} = this.SafeString(params, "options") if IsTrue(!IsEqual(options, nil)) { AddElementToObject(request, "options", []interface{}{options}) } } response:= (<-this.PrivatePostV1OrderNew(this.Extend(request, params))) PanicOnError(response) // // { // "order_id":"106027397702", // "id":"106027397702", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"2877.48", // "side":"sell", // "type":"exchange limit", // "timestamp":"1650398122", // "timestampms":1650398122308, // "is_live":false, // "is_cancelled":false, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0.014434", // "client_order_id":"1650398121695", // "options":[], // "price":"2800.00", // "original_amount":"0.014434", // "remaining_amount":"0" // } // ch <- this.ParseOrder(response) return nil }() return ch } /** * @method * @name gemini#cancelOrder * @description cancels an open order * @see https://docs.gemini.com/rest-api/#cancel-order * @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} */ func (this *gemini) CancelOrder(id interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) symbol := GetArg(optionalArgs, 0, nil) _ = symbol params := GetArg(optionalArgs, 1, map[string]interface{} {}) _ = params retRes16318 := (<-this.LoadMarkets()) PanicOnError(retRes16318) var request interface{} = map[string]interface{} { "order_id": id, } response:= (<-this.PrivatePostV1OrderCancel(this.Extend(request, params))) PanicOnError(response) // // { // "order_id":"106028543717", // "id":"106028543717", // "symbol":"etheur", // "exchange":"gemini", // "avg_execution_price":"0.00", // "side":"buy", // "type":"exchange limit", // "timestamp":"1650398446", // "timestampms":1650398446375, // "is_live":false, // "is_cancelled":true, // "is_hidden":false, // "was_forced":false, // "executed_amount":"0", // "client_order_id":"1650398445709", // "reason":"Requested", // "options":[], // "price":"2000.00", // "original_amount":"0.01", // "remaining_amount":"0.01" // } // ch <- this.ParseOrder(response) return nil }() return ch } /** * @method * @name gemini#fetchMyTrades * @description fetch all trades made by the user * @see https://docs.gemini.com/rest-api/#get-past-trades * @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 * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ func (this *gemini) FetchMyTrades(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) symbol := GetArg(optionalArgs, 0, nil) _ = symbol since := GetArg(optionalArgs, 1, nil) _ = since limit := GetArg(optionalArgs, 2, nil) _ = limit params := GetArg(optionalArgs, 3, map[string]interface{} {}) _ = params if IsTrue(IsEqual(symbol, nil)) { panic(ArgumentsRequired(Add(this.Id, " fetchMyTrades() requires a symbol argument"))) } retRes16788 := (<-this.LoadMarkets()) PanicOnError(retRes16788) var market interface{} = this.Market(symbol) var request interface{} = map[string]interface{} { "symbol": GetValue(market, "id"), } if IsTrue(!IsEqual(limit, nil)) { AddElementToObject(request, "limit_trades", limit) } if IsTrue(!IsEqual(since, nil)) { AddElementToObject(request, "timestamp", this.ParseToInt(Divide(since, 1000))) } response:= (<-this.PrivatePostV1Mytrades(this.Extend(request, params))) PanicOnError(response) ch <- this.ParseTrades(response, market, since, limit) return nil }() return ch } /** * @method * @name gemini#withdraw * @description make a withdrawal * @see https://docs.gemini.com/rest-api/#withdraw-crypto-funds * @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} */ func (this *gemini) Withdraw(code interface{}, amount interface{}, address interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) tag := GetArg(optionalArgs, 0, nil) _ = tag params := GetArg(optionalArgs, 1, map[string]interface{} {}) _ = params tagparamsVariable := this.HandleWithdrawTagAndParams(tag, params); tag = GetValue(tagparamsVariable,0); params = GetValue(tagparamsVariable,1) this.CheckAddress(address) retRes17088 := (<-this.LoadMarkets()) PanicOnError(retRes17088) var currency interface{} = this.Currency(code) var request interface{} = map[string]interface{} { "currency": GetValue(currency, "id"), "amount": amount, "address": address, } response:= (<-this.PrivatePostV1WithdrawCurrency(this.Extend(request, params))) PanicOnError(response) // // for BTC // { // "address":"mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR", // "amount":"1", // "withdrawalId":"02176a83-a6b1-4202-9b85-1c1c92dd25c4", // "message":"You have requested a transfer of 1 BTC to mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR. This withdrawal will be sent to the blockchain within the next 60 seconds." // } // // for ETH // { // "address":"0xA63123350Acc8F5ee1b1fBd1A6717135e82dBd28", // "amount":"2.34567", // "txHash":"0x28267179f92926d85c5516bqc063b2631935573d8915258e95d9572eedcc8cc" // } // // for error (other variations of error messages are also expected) // { // "result":"error", // "reason":"CryptoAddressWhitelistsNotEnabled", // "message":"Cryptocurrency withdrawal address whitelists are not enabled for account 24. Please contact support@gemini.com for information on setting up a withdrawal address whitelist." // } // var result interface{} = this.SafeString(response, "result") if IsTrue(IsEqual(result, "error")) { panic(ExchangeError(Add(Add(this.Id, " withdraw() failed: "), this.Json(response)))) } ch <- this.ParseTransaction(response, currency) return nil }() return ch } func (this *gemini) Nonce() interface{} { var nonceMethod interface{} = this.SafeString(this.Options, "nonce", "milliseconds") if IsTrue(IsEqual(nonceMethod, "milliseconds")) { return this.Milliseconds() } return this.Seconds() } /** * @method * @name gemini#fetchDepositsWithdrawals * @description fetch history of deposits and withdrawals * @see https://docs.gemini.com/rest-api/#transfers * @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined * @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined * @param {int} [limit] max number of deposit/withdrawals to return, default is undefined * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure} */ func (this *gemini) FetchDepositsWithdrawals(optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) code := GetArg(optionalArgs, 0, nil) _ = code since := GetArg(optionalArgs, 1, nil) _ = since limit := GetArg(optionalArgs, 2, nil) _ = limit params := GetArg(optionalArgs, 3, map[string]interface{} {}) _ = params retRes17668 := (<-this.LoadMarkets()) PanicOnError(retRes17668) var request interface{} = map[string]interface{} {} if IsTrue(!IsEqual(limit, nil)) { AddElementToObject(request, "limit_transfers", limit) } if IsTrue(!IsEqual(since, nil)) { AddElementToObject(request, "timestamp", since) } response:= (<-this.PrivatePostV1Transfers(this.Extend(request, params))) PanicOnError(response) ch <- this.ParseTransactions(response) return nil }() return ch } func (this *gemini) ParseTransaction(transaction interface{}, optionalArgs ...interface{}) interface{} { // // withdraw // // for BTC // { // "address":"mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR", // "amount":"1", // "withdrawalId":"02176a83-a6b1-4202-9b85-1c1c92dd25c4", // "message":"You have requested a transfer of 1 BTC to mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR. This withdrawal will be sent to the blockchain within the next 60 seconds." // } // // for ETH // { // "address":"0xA63123350Acc8F5ee1b1fBd1A6717135e82dBd28", // "amount":"2.34567", // "txHash":"0x28267179f92926d85c5516bqc063b2631935573d8915258e95d9572eedcc8cc" // } // currency := GetArg(optionalArgs, 0, nil) _ = currency var timestamp interface{} = this.SafeInteger(transaction, "timestampms") var currencyId interface{} = this.SafeString(transaction, "currency") var code interface{} = this.SafeCurrencyCode(currencyId, currency) var address interface{} = this.SafeString(transaction, "destination") var typeVar interface{} = this.SafeStringLower(transaction, "type") // if status field is available, then it's complete var statusRaw interface{} = this.SafeString(transaction, "status") var fee interface{} = nil var feeAmount interface{} = this.SafeNumber(transaction, "feeAmount") if IsTrue(!IsEqual(feeAmount, nil)) { fee = map[string]interface{} { "cost": feeAmount, "currency": code, } } return map[string]interface{} { "info": transaction, "id": this.SafeString2(transaction, "eid", "withdrawalId"), "txid": this.SafeString(transaction, "txHash"), "timestamp": timestamp, "datetime": this.Iso8601(timestamp), "network": nil, "address": address, "addressTo": nil, "addressFrom": nil, "tag": nil, "tagTo": nil, "tagFrom": nil, "type": typeVar, "amount": this.SafeNumber(transaction, "amount"), "currency": code, "status": this.ParseTransactionStatus(statusRaw), "updated": nil, "internal": nil, "comment": this.SafeString(transaction, "message"), "fee": fee, } } func (this *gemini) ParseTransactionStatus(status interface{}) interface{} { var statuses interface{} = map[string]interface{} { "Advanced": "ok", "Complete": "ok", } return this.SafeString(statuses, status, status) } func (this *gemini) ParseDepositAddress(depositAddress interface{}, optionalArgs ...interface{}) interface{} { // // { // "address": "0xed6494Fe7c1E56d1bd6136e89268C51E32d9708B", // "timestamp": "1636813923098", // "addressVersion": "eV1" } // } // currency := GetArg(optionalArgs, 0, nil) _ = currency var address interface{} = this.SafeString(depositAddress, "address") var code interface{} = this.SafeCurrencyCode(nil, currency) return map[string]interface{} { "currency": code, "network": nil, "address": address, "tag": nil, "info": depositAddress, } } /** * @method * @name gemini#fetchDepositAddress * @see https://docs.gemini.com/rest-api/#get-deposit-addresses * @description fetch the deposit address for a currency associated with this account * @param {string} code unified currency code * @param {object} [params] extra parameters specific to the endpoint * @param {string} [params.network] *required* The chain of currency * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure} */ func (this *gemini) FetchDepositAddress(code interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes18748 := (<-this.LoadMarkets()) PanicOnError(retRes18748) groupedByNetwork:= (<-this.FetchDepositAddressesByNetwork(code, params)) PanicOnError(groupedByNetwork) var networkCode interface{} = nil networkCodeparamsVariable := this.HandleNetworkCodeAndParams(params); networkCode = GetValue(networkCodeparamsVariable,0); params = GetValue(networkCodeparamsVariable,1) var networkGroup interface{} = this.IndexBy(this.SafeValue(groupedByNetwork, networkCode), "currency") ch <- this.SafeValue(networkGroup, code) return nil }() return ch } /** * @method * @name gemini#fetchDepositAddressesByNetwork * @description fetch a dictionary of addresses for a currency, indexed by network * @see https://docs.gemini.com/rest-api/#get-deposit-addresses * @param {string} code unified currency code of the currency for the deposit address * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.network] *required* The chain of currency * @returns {object} a dictionary of [address structures]{@link https://docs.ccxt.com/#/?id=address-structure} indexed by the network */ func (this *gemini) FetchDepositAddressesByNetwork(code interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes18938 := (<-this.LoadMarkets()) PanicOnError(retRes18938) var currency interface{} = this.Currency(code) code = GetValue(currency, "code") var networkCode interface{} = nil networkCodeparamsVariable := this.HandleNetworkCodeAndParams(params); networkCode = GetValue(networkCodeparamsVariable,0); params = GetValue(networkCodeparamsVariable,1) if IsTrue(IsEqual(networkCode, nil)) { panic(ArgumentsRequired(Add(this.Id, " fetchDepositAddresses() requires a network parameter"))) } var networkId interface{} = this.NetworkCodeToId(networkCode) var request interface{} = map[string]interface{} { "network": networkId, } response:= (<-this.PrivatePostV1AddressesNetwork(this.Extend(request, params))) PanicOnError(response) var results interface{} = this.ParseDepositAddresses(response, []interface{}{code}, false, map[string]interface{} { "network": networkCode, "currency": code, }) ch <- this.GroupBy(results, "network") return nil }() return ch } func (this *gemini) Sign(path interface{}, optionalArgs ...interface{}) interface{} { api := GetArg(optionalArgs, 0, "public") _ = api method := GetArg(optionalArgs, 1, "GET") _ = method params := GetArg(optionalArgs, 2, map[string]interface{} {}) _ = params headers := GetArg(optionalArgs, 3, nil) _ = headers body := GetArg(optionalArgs, 4, nil) _ = body var url interface{} = Add("/", this.ImplodeParams(path, params)) var query interface{} = this.Omit(params, this.ExtractParams(path)) if IsTrue(IsEqual(api, "private")) { this.CheckRequiredCredentials() var apiKey interface{} = this.ApiKey if IsTrue(IsLessThan(GetIndexOf(apiKey, "account"), 0)) { panic(AuthenticationError(Add(this.Id, " sign() requires an account-key, master-keys are not-supported"))) } var nonce interface{} = ToString(this.Nonce()) var request interface{} = this.Extend(map[string]interface{} { "request": url, "nonce": nonce, }, query) var payload interface{} = this.Json(request) payload = this.StringToBase64(payload) var signature interface{} = this.Hmac(this.Encode(payload), this.Encode(this.Secret), sha384) headers = map[string]interface{} { "Content-Type": "text/plain", "X-GEMINI-APIKEY": this.ApiKey, "X-GEMINI-PAYLOAD": payload, "X-GEMINI-SIGNATURE": signature, } } else { if IsTrue(GetArrayLength(ObjectKeys(query))) { url = Add(url, Add("?", this.Urlencode(query))) } } url = Add(GetValue(GetValue(this.Urls, "api"), api), url) if IsTrue(IsTrue((IsEqual(method, "POST"))) || IsTrue((IsEqual(method, "DELETE")))) { body = this.Json(query) } return map[string]interface{} { "url": url, "method": method, "body": body, "headers": headers, } } func (this *gemini) HandleErrors(httpCode interface{}, reason interface{}, url interface{}, method interface{}, headers interface{}, body interface{}, response interface{}, requestHeaders interface{}, requestBody interface{}) interface{} { if IsTrue(IsEqual(response, nil)) { if IsTrue(IsString(body)) { var feedback interface{} = Add(Add(this.Id, " "), body) this.ThrowBroadlyMatchedException(GetValue(this.Exceptions, "broad"), body, feedback) } return nil // fallback to default error handler } // // { // "result": "error", // "reason": "BadNonce", // "message": "Out-of-sequence nonce <1234> precedes previously used nonce <2345>" // } // var result interface{} = this.SafeString(response, "result") if IsTrue(IsEqual(result, "error")) { var reasonInner interface{} = this.SafeString(response, "reason") var message interface{} = this.SafeString(response, "message") var feedback interface{} = Add(Add(this.Id, " "), message) this.ThrowExactlyMatchedException(GetValue(this.Exceptions, "exact"), reasonInner, feedback) this.ThrowExactlyMatchedException(GetValue(this.Exceptions, "exact"), message, feedback) this.ThrowBroadlyMatchedException(GetValue(this.Exceptions, "broad"), message, feedback) panic(ExchangeError(feedback)) } return nil } /** * @method * @name gemini#createDepositAddress * @description create a currency deposit address * @see https://docs.gemini.com/rest-api/#new-deposit-address * @param {string} code unified currency code of the currency for the deposit address * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure} */ func (this *gemini) CreateDepositAddress(code interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) params := GetArg(optionalArgs, 0, map[string]interface{} {}) _ = params retRes19838 := (<-this.LoadMarkets()) PanicOnError(retRes19838) var currency interface{} = this.Currency(code) var request interface{} = map[string]interface{} { "currency": GetValue(currency, "id"), } response:= (<-this.PrivatePostV1DepositCurrencyNewAddress(this.Extend(request, params))) PanicOnError(response) var address interface{} = this.SafeString(response, "address") this.CheckAddress(address) ch <- map[string]interface{} { "currency": code, "address": address, "tag": nil, "info": response, } return nil }() return ch } /** * @method * @name gemini#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://docs.gemini.com/rest-api/#candles * @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 * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ func (this *gemini) FetchOHLCV(symbol interface{}, optionalArgs ...interface{}) <- chan interface{} { ch := make(chan interface{}) go func() interface{} { defer close(ch) defer ReturnPanicError(ch) timeframe := GetArg(optionalArgs, 0, "1m") _ = timeframe since := GetArg(optionalArgs, 1, nil) _ = since limit := GetArg(optionalArgs, 2, nil) _ = limit params := GetArg(optionalArgs, 3, map[string]interface{} {}) _ = params retRes20128 := (<-this.LoadMarkets()) PanicOnError(retRes20128) var market interface{} = this.Market(symbol) var timeframeId interface{} = this.SafeString(this.Timeframes, timeframe, timeframe) var request interface{} = map[string]interface{} { "timeframe": timeframeId, "symbol": GetValue(market, "id"), } response:= (<-this.PublicGetV2CandlesSymbolTimeframe(this.Extend(request, params))) PanicOnError(response) // // [ // [1591515000000,0.02509,0.02509,0.02509,0.02509,0], // [1591514700000,0.02503,0.02509,0.02503,0.02509,44.6405], // [1591514400000,0.02503,0.02503,0.02503,0.02503,0], // ] // ch <- this.ParseOHLCVs(response, market, timeframe, since, limit) return nil }() return ch } func (this *gemini) Init(userConfig map[string]interface{}) { this.Exchange = Exchange{} this.Exchange.InitParent(userConfig, this.Describe().(map[string]interface{}), this) this.Exchange.DerivedExchange = this }