Gemini

[Layer.zip (updated for deposits) generated from Docker allows you to use gemini Python library when uploaded as a Layer in AWS - instructions for how to generate your own here: https://dev.to/mmascioni/using-external-python-packages-with-aws-lambda-layers-526o](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/04373a20-8a41-41e1-aff3-97ec40c278a2/layer.zip)

Layer.zip (updated for deposits) generated from Docker allows you to use gemini Python library when uploaded as a Layer in AWS - instructions for how to generate your own here: https://dev.to/mmascioni/using-external-python-packages-with-aws-lambda-layers-526o

FAQs: https://rhett.blog/2021/07/08/gemini-api-faqs/

For DEVS: https://github.com/TheTallMan67/Gemini-API-Functions-for-AWS

Buy Bitcoin from Gemini

import json
import gemini

public_key = ""  
private_key = ""
symbol = "BTCUSD"
tick_size = 8
quote_currency_price_increment = 2
#update symbol based on what crypto/fiat pair you want to buy. Default is BTCUSD, change to BTCEUR for Euros or ETHUSD for Ethereum (for example) - see all possibilities down in symbols and minimums link
#update tick_size and quote_currency_price_increment based on what crypto-pair you are buying. BTC is 8 - in the doc it says 1e-8 you want the number after e-. Or in the case of .01 you want 2 (because .01 is 1e-2) 
#Check out the API link below to see what you need for your pair
#<https://docs.gemini.com/rest-api/#symbols-and-minimums>

def _buyBitcoin(buy_size,pub_key, priv_key):
    # Set up a buy for 0.999 times the current price add more decimals for a higher price and faster fill, if the price is too close to spot your order won't post. 
    # Lower factor makes the order cheaper but fills quickly (0.5 would set an order for half the price and so your order could take months/years/never to fill)
    trader = gemini.PrivateClient(pub_key, priv_key)
    symbol_spot_price = float(trader.get_ticker(symbol)['ask'])
    print(symbol_spot_price)
    factor = 0.999
    #to set a limit order at a fixed price (ie. $55,525) set execution_price = "55525.00" or execution_price = str(55525.00)
    execution_price = str(round(symbol_spot_price*factor,quote_currency_price_increment))

    #set amount to the most precise rounding (tick_size) and multiply by 0.999 for fee inclusion - if you make an order for $20.00 there should be $19.98 coin bought and $0.02 (0.10% fee)
    amount = round((buy_size*0.999)/float(execution_price),tick_size)
		
    #execute maker buy with the appropriate symbol, amount, and calculated price
    buy = trader.new_order(symbol, str(amount), execution_price, "buy", ["maker-or-cancel"])
    print(f'Maker Buy: {buy}')

def lambda_handler(event, context):
    _buyBitcoin(20, public_key, private_key)
    return {
        'statusCode': 200,
        'body': json.dumps('End of script')
    }

Buy ETH from Gemini

import json
import gemini

public_key = ""  
private_key = ""
symbol = "ETHUSD"
tick_size = 6
quote_currency_price_increment = 2
#update symbol based on what crypto/fiat pair you want to buy. Default is BTCUSD, change to BTCEUR for Euros or ETHUSD for Ethereum (for example) - see all possibilities down in symbols and minimums link
#update tick_size and quote_currency_price_increment based on what crypto-pair you are buying. BTC is 8 - in the doc it says 1e-8 you want the number after e-. Or in the case of .01 you want 2 (because .01 is 1e-2) 
#Check out the API link below to see what you need for your pair
#<https://docs.gemini.com/rest-api/#symbols-and-minimums>

def _buyEtherium(buy_size,pub_key, priv_key):
    # Set up a buy for the current price
    trader = gemini.PrivateClient(pub_key, priv_key)
    factor = 0.999
    #to set a limit order at a fixed price (ie. $55,525) set execution_price = "55525.00" or execution_price = str(55525.00)
    price = str(round(float(trader.get_ticker(symbol)['ask'])*factor,quote_currency_price_increment))

    #most precise rounding + *.999 for fee inclusion
    eth_amount = round((buy_size*factor)/float(price),tick_size)

    #execute maker buy, round to 8 decimal places for precision, multiply price by 2 so your limit order always gets fully filled
    buy = trader.new_order(symbol, str(eth_amount), price, "buy", ["maker-or-cancel"])
    print(f'Maker Buy: {buy}')

def lambda_handler(event, context):
    _buyEtherium(10, public_key, private_key)
    return {
        'statusCode': 200,
        'body': json.dumps('End of script')
    }

Withdraw From Gemini to One Address

import json
import gemini

public_key = ""  
private_key = ""
trader = gemini.PrivateClient(public_key, private_key)

#withdraws full available balance of specified coin to given address
def _withdrawFullCoinBalance(coin, address):
    amount = "0"
    for currency in trader.get_balance():
        if(currency['currency'] == coin):
            amount = currency['availableForWithdrawal']
            print(f'Amount Available for Withdrawal: {amount}')
    
    #Replace the amount variable below with ".001" to withdraw .001 BTC - change the amount if you want to withdraw some static amount
    withdraw = trader.withdraw_to_address(coin, address, amount)
    print(withdraw)

def lambda_handler(event, context):
    #Add addresses below 
    #MAKE SURE THAT YOUR WALLET ADDRESS IS FOR THE SAME TOKEN AS THE WITHDRAWAL SYMBOL OR YOU COULD LOSE FUNDS
    #(ie. in _withdrawPartialCoinBalance(bitcoin_withdrawal_symbol, btc_address, .75) both btc_address and bitcoin_withdrawal_symbol reference the same coin (BTC))

    bitcoin_withdrawal_symbol = "BTC"
    ethereum_withdrawal_symbol = "ETH"
    btc_address = ''
    eth_address = ''
    _withdrawFullCoinBalance(bitcoin_withdrawal_symbol, btc_address)
    _withdrawFullCoinBalance(ethereum_withdrawal_symbol, eth_address)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Withdraw From Gemini to Multiple Addresses

import json
import gemini

public_key = ""  
private_key = ""
trader = gemini.PrivateClient(public_key, private_key)

#withdraws full available balance of specified coin to given address
def _withdrawPartialCoinBalance(coin, address, percentage):
    amount = "0"
    for currency in trader.get_balance():
        if(currency['currency'] == coin):
            amount = currency['availableForWithdrawal'] * percentage
            print(f'Amount Available for Withdrawal: {amount}')
    
    #Replace the amount variable below with ".001" to withdraw .001 BTC - change the amount if you want to withdraw some static amount
    withdraw = trader.withdraw_to_address(coin, address, amount)

def lambda_handler(event, context):
    #Add addresses below 
    #MAKE SURE THAT YOUR WALLET ADDRESS IS FOR THE SAME TOKEN AS THE WITHDRAWAL SYMBOL OR YOU COULD LOSE FUNDS
    #(ie. in _withdrawPartialCoinBalance(bitcoin_withdrawal_symbol, btc_address, .75) both btc_address and bitcoin_withdrawal_symbol reference the same coin (BTC))

    bitcoin_withdrawal_symbol = "BTC"
    #for full list of symbols -> <https://docs.gemini.com/rest-api/#symbols-and-minimums>
 
    btc_address = ''
    btc_address_2 = ''

    #withdrawals 75% of your available balance
    _withdrawPartialCoinBalance(bitcoin_withdrawal_symbol, btc_address, .75)
    #withdrawals 100% of the 25% of your original remaining balance
    _withdrawPartialCoinBalance(bitcoin_withdrawal_symbol, btc_address_2, 1)
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Sell Bitcoin - Gemini

import json
import gemini

public_key = ""  
private_key = ""
symbol = 'BTCUSD'
tick_size = 8
quote_currency_price_increment = 2
#update symbol based on what crypto/fiat pair you want to buy. Default is BTCUSD, change to BTCEUR for Euros or ETHUSD for Ethereum (for example) - see all possibilities down in symbols and minimums link
#update tick_size and quote_currency_price_increment based on what crypto-pair you are buying. BTC is 8 - in the doc it says 1e-8 you want the number after e-. Or in the case of .01 you want 2 (because .01 is 1e-2) 
#Check out the API link below to see what you need for your pair
#<https://docs.gemini.com/rest-api/#symbols-and-minimums>

def _sellBitcoin(sell_size,pub_key, priv_key):
    # Set up a sell for 1.001X above the current price
    # Higher factor makes the order price higher but fills slower (2 would set an order for double the price and so your order could take months/years/never to fill)
    trader = gemini.PrivateClient(pub_key, priv_key)
    symbol_spot_price = float(trader.get_ticker(symbol)['ask'])
    factor = 1.001
    #to set a limit order at a fixed price (ie. $55,525) set execution_price = "55525.00" or execution_price = str(55525.00)
    execution_price = str(round(symbol_spot_price*factor,2))

    #most precise rounding + *.999 for fee inclusion
    amount = round((sell_size*.999)/float(price),tick_size)

    #execute maker sell, round to 8 decimal places for precision, multiply price by 2 so your limit order always gets fully filled
    sell = trader.new_order(symbol, str(amount), price, "sell", ["maker-or-cancel"])
    print(f'Maker Sell: {sell}')
    return [btc_amount, price]

def lambda_handler(event, context):
    message = _sellBitcoin(20, public_key, private_key)
    return {
        'statusCode': 200,
        'body': json.dumps(f'You sold {message[0]} Bitcoin for {message[1]}. You monster.')
    }

Convert GUSD to USD (For Automating Deposits)

import json
import gemini

public_key = ''
private_key = ''

#This function converts all your GUSD to USD
def _convertGUSDtoUSD(pub_key, priv_key):
    gusd_balance = 0
    trader = gemini.PrivateClient(pub_key, priv_key)
    if(list((type['available'] for type in  trader.get_balance() if type['currency'] == 'GUSD'))):
        gusd_balance = str(list((type['available'] for type in  trader.get_balance() if type['currency'] == 'GUSD'))[0])
    #use "buy" to convert USD to GUSD
    #use "sell" to convert GUSD into USD
    #replace gusd_balance below to transfer a static amount, use gusd_balance to transfer all your GUSD to USD
    results = trader.wrap_order(gusd_balance, "sell")
    print(results)

def lambda_handler(event, context):
    _convertGUSDtoUSD(public_key, private_key)
    return {
        'statusCode': 200,
        'body': json.dumps('End of script')
    }

Update Bitcoin GSheet - Gemini

import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime
import gemini

public_key = ""  
private_key = ""

def _addTransaction(transaction):
    #populate transaction details
    transaction_date = str(datetime.fromtimestamp(transaction['timestamp']).date())
    transaction_id = float(transaction['tid'])
    provider = "Gemini"
    quantity = float(transaction['amount'])
    btc_price = float(transaction['price'])
    fee = float(transaction['fee_amount'])
    usd_amount = quantity * btc_price + fee

    #populate with new row
    return [transaction_date, transaction_id, provider, quantity, btc_price, usd_amount, fee]
    
def _authenticateSpreadsheet():
    #Set up access to the spreadsheet
    scope = ["<https://spreadsheets.google.com/feeds>",
            '<https://www.googleapis.com/auth/spreadsheets>',
            "<https://www.googleapis.com/auth/drive.file>",
            "<https://www.googleapis.com/auth/drive>"]
    creds = ServiceAccountCredentials.from_json_keyfile_name("sheets_creds.json", scope)
    client = gspread.authorize(creds)
    return client.open("The Public Definitive Bitcoin Sheet").worksheet("BTC Buy Audit File")

def populateBTC(pub_key, priv_key):
    audit_file = _authenticateSpreadsheet()
    num_rows_added = 0
    trader = gemini.PrivateClient(pub_key, private_key)
    buys = trader.get_past_trades("BTCUSD")[::-1]
    last_gemini_transaction = (list(filter(lambda gemini: gemini['Provider'] == 'Gemini', audit_file.get_all_records()[-50:]))[-1]['Transaction ID'])
    for buy in buys:
        if(buy['tid'] > last_gemini_transaction):
            audit_file.append_row(_addTransaction(buy), value_input_option="USER_ENTERED")
            num_rows_added += 1
    return num_rows_added
    
def lambda_handler(event, context):
    num = populateBTC(public_key, private_key)
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps(f'{num} transactions added!')
    }

Convert BAT to BTC - Gemini

import json
import gemini
from math import floor

public_key = ""  
private_key = ""
symbol = 'BATBTC'
tick_size = 6
quote_currency_price_increment = 8
#update symbol based on what crypto/fiat pair you want to buy. Default is BATBTC, change to BATETH for ETH or BATUSD for USD (for example) - see all possibilities down in symbols and minimums link
#update tick size based on what crypto-pair you are buying. All BAT pairs are 6. Check out the API link below to see what you need for your pair
#update you quote_currency_price_increment based on the BAT pair you're trading. BTC is 8, ETH is 7, USD is 5
#<https://docs.gemini.com/rest-api/#symbols-and-minimums>

def _convertBAT(pub_key, priv_key, sell_size=0):
    bat_balance = 0
    trader = gemini.PrivateClient(pub_key, priv_key)
    if(list((type['available'] for type in  trader.get_balance() if type['currency'] == 'BAT'))):
        bat_balance = str(list((type['available'] for type in  trader.get_balance() if type['currency'] == 'BAT'))[0])
        print(f"BAT balance = {bat_balance}")
    if sell_size == 0:
        sell_size = (floor(float(bat_balance)*(10**(tick_size))))/(10**(tick_size))
        print(f"Sell size = {sell_size}")

    price = str(round(float(trader.get_ticker(symbol)['ask'])*0.999,quote_currency_price_increment))
    print(f"Price: {price}")

    #execute maker sell
    sell = trader.new_order(symbol, str(sell_size), price, "sell", ["maker-or-cancel"])
    print(f'Maker Sell: {sell}')
    return [sell_size, price]

def lambda_handler(event, context):
    #Provide optional third parameter sell size to _convertBAT to only convert a BTC sized portion of your BAT
    #ie. _convertBAT(public_key, private_key, .00001) to sell .00001 BTC of your BAT stack
    message = _convertBAT(public_key, private_key)
    return {
        'statusCode': 200,
        'body': json.dumps(f'Placed maker sell order for {symbol}.')
    }