mirror of
https://github.com/MAGICGrants/autoforward-autoconvert.git
synced 2026-01-08 21:18:09 -05:00
Add settlement_currency
This commit is contained in:
@@ -15,6 +15,7 @@ KRAKEN_API_SECRET=""
|
||||
|
||||
MAX_NETWORK_FEE_PERCENT="5"
|
||||
MAX_SLIPPAGE_PERCENT="0.5"
|
||||
SETTLEMENT_CURRENCY="USD"
|
||||
|
||||
BITCOIN_FEE_SOURCE="https://mempool.space/api/v1/fees/recommended"
|
||||
BITCOIN_FEE_RATE="halfHourFee"
|
||||
|
||||
21
README.md
21
README.md
@@ -1,6 +1,6 @@
|
||||
# autoforward-autoconvert
|
||||
|
||||
Programs to auto-forward BTC and XMR wallets to Kraken, and then auto-convert to USD.
|
||||
Programs to auto-forward BTC, LTC, LTC-MWEB, and XMR wallets to Kraken, and then auto-convert to your preferred settlement currency (e.g. USD, USDT, BTC).
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -29,6 +29,7 @@ Create a `.env` file as a copy of `.env.example` and set the values for the empt
|
||||
| `LITECOIN_ELECTRUM_SERVER_ADDRESS` | **No** | - | The address of a Litecoin Electrum server you own or trust. E.g.: `localhost:50001:t` (no SSL) or `my.electrum.server:50001:s` (SSL). By leaving this blank you're letting Electrum select a random server for you, which may be a privacy concern. |
|
||||
| `MAX_NETWORK_FEE_PERCENT` | **No** | `5` | The maximum accepted miner fee percent when auto-forwarding. Not applied to XMR. |
|
||||
| `MAX_SLIPPAGE_PERCENT` | **No** | `0.5` | The maximum accepted slippage percent when auto-converting. |
|
||||
| `SETTLEMENT_CURRENCY` | **No** | `USD` | The currency you wish to convert to. If there isn't a direct trading pair, it attempts to trade through USD first, e.g. XMR->USD->DAI. |
|
||||
| `BITCOIN_FEE_SOURCE` | **No** | `https://mempool.space/api/v1/fees/recommended` | The fee API source to use for Bitcoin transactions. |
|
||||
| `BITCOIN_FEE_RATE` | **No** | `halfHourFee` | The fee rate to use in the Bitcoin fee source API response. |
|
||||
| `LITECOIN_FEE_SOURCE` | **No** | `https://litecoinspace.org/api/v1/fees/recommended` | The fee API source to use for Litecoin transactions. |
|
||||
@@ -57,11 +58,25 @@ Change the seeds in the `.env` file and start all services again:
|
||||
$ docker-compose --env-file .env up -d
|
||||
```
|
||||
|
||||
# Contributing
|
||||
## Trading Strategy
|
||||
|
||||
The trading strategy utilized in this program is as follows:
|
||||
|
||||
- Fetch the current balance to sell.
|
||||
- First try to sell with one trade, e.g. XMR->USD.
|
||||
- If that fails, try to sell via USD, e.g. XMR->USD->DAI.
|
||||
- Sell by taking as many maarket trades as possible to not move the price down more than 0.5% from the calculated mid price.
|
||||
- Wait a random amount of time before trying again between 30-90 seconds.
|
||||
|
||||
We strongly recommend running this program with a dedicated Kraken account to ensure that it does not interfere with any of your other activities.
|
||||
|
||||
This trading stategy may not be optimal for your needs. You can configure the `MAX_NETWORK_FEE_PERCENT` environment variable. For illiquid trading pairs that regularly have bid-ask spreads exceeding 1%, consider a higher value than 0.5%. You should consider a different trading strategy if you are sensitive to taker fees.
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests welcome!
|
||||
Thanks for supporting MAGIC Grants.
|
||||
|
||||
# License
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
@@ -13,39 +13,68 @@ order_min = {
|
||||
'XMR': 0.03
|
||||
}
|
||||
|
||||
def get_balance(asset: Literal['XBT', 'LTC', 'XMR']) -> str:
|
||||
def get_balance(settlement_kraken_ticker) -> str:
|
||||
balances = util.kraken_request('/0/private/Balance')
|
||||
balance = '0'
|
||||
|
||||
if f'X{asset}' in balances:
|
||||
balance = balances[f'X{asset}']
|
||||
if f'{settlement_kraken_ticker}' in balances:
|
||||
balance = balances[f'{settlement_kraken_ticker}']
|
||||
|
||||
return balance
|
||||
|
||||
def get_orderbook(asset: Literal['XBT', 'LTC', 'XMR']):
|
||||
return util.kraken_request('/0/public/Depth?count=1', {'pair': f'{asset}USD'})[f'X{asset}ZUSD']
|
||||
def get_orderbook(asset: Literal['XBT', 'LTC', 'XMR'], settlement_currency='USD', settlement_kraken_ticker='ZUSD'):
|
||||
return util.kraken_request('/0/public/Depth?count=1', {'pair': f'{asset}{settlement_currency}'})[f'X{asset}{settlement_kraken_ticker}'] #TODO check
|
||||
|
||||
def attempt_sell(asset: Literal['XBT', 'XMR']):
|
||||
def make_trade(orderbook, payload):
|
||||
mid_market_price = float(orderbook['bids'][0][0]) + ((float(orderbook['asks'][0][0]) - float(orderbook['bids'][0][0])) / 2) # Example 212.55+((212.72-212.55)/2) = 212.635
|
||||
limit_price = mid_market_price * (1-env.MAX_SLIPPAGE_PERCENT/100) # Example 212.365*(1-0.5/100) = 211.303175
|
||||
payload['price'] = limit_price
|
||||
util.kraken_request('/0/private/AddOrder', payload)
|
||||
print(util.get_time(), f'Selling up to {balance} for pair {payload['pair']} at no less than {limit_price}')
|
||||
|
||||
def attempt_sell(asset: Literal['XBT', 'LTC', 'XMR']):
|
||||
balance = get_balance(f'X{asset}')
|
||||
if balance < order_min[asset]:
|
||||
print(util.get_time(), f'Not enough {asset} balance to sell. (Balance: {balance}, Min order: {order_min[asset]})')
|
||||
return
|
||||
|
||||
orderbook = get_orderbook(asset)
|
||||
mid_market_price = float(orderbook['bids'][0][0]) + ((float(orderbook['asks'][0][0]) - float(orderbook['bids'][0][0])) / 2) # Example 212.55+((212.72-212.55)/2) = 212.635
|
||||
limit_price = mid_market_price * (1-env.MAX_SLIPPAGE_PERCENT/100) # Example 212.365*(1-0.5/100) = 211.303175
|
||||
|
||||
settlement_currency = env.SETTLEMENT_CURRENCY
|
||||
# https://support.kraken.com/hc/en-us/articles/360001206766-Bitcoin-currency-code-XBT-vs-BTC
|
||||
if settlement_currency in ['AUD', 'CAD', 'EUR', 'GBP', 'JPY', 'USD']:
|
||||
settlement_kraken_ticker = 'Z' + settlement_currency
|
||||
elif settlement_currency in ['ETC', 'ETH', 'LTC', 'MLN', 'REP', 'XBT', 'XDG', 'XLM', 'XMR', 'XRP', 'ZEC']:
|
||||
settlement_kraken_ticker = 'X' + settlement_currency
|
||||
else:
|
||||
settlement_kraken_ticker = settlement_currency
|
||||
|
||||
payload = {
|
||||
'ordertype': 'limit',
|
||||
'type': 'sell',
|
||||
'pair': f'{asset}USD',
|
||||
'pair': f'{asset}{settlement_currency}',
|
||||
'volume': balance,
|
||||
'price': limit_price,
|
||||
'timeinforce': 'IOC', # Immediately fill order to extent possible, then kill
|
||||
'timeinforce': 'IOC', # Immediately fill order to extent possible, then cancel
|
||||
'validate': true # Remove this after tested
|
||||
}
|
||||
|
||||
util.kraken_request('/0/private/AddOrder', payload)
|
||||
print(util.get_time(), f'Selling up to {balance} at no less than {limit_price}')
|
||||
if settlement_currency != asset:
|
||||
try:
|
||||
orderbook = get_orderbook(asset, settlement_currency, settlement_kraken_ticker)
|
||||
if orderbook.status_code == 200:
|
||||
make_trade(orderbook, payload)
|
||||
else:
|
||||
raise Exception
|
||||
except:
|
||||
print(f'No direct trading pair for {payload['pair']}, trying USD')
|
||||
payload['pair'] = f'{asset}USD'
|
||||
orderbook = get_orderbook(asset)
|
||||
make_trade(orderbook, payload)
|
||||
payload['pair'] = f'{settlement_currency}USD'
|
||||
payload['balance'] = get_balance('ZUSD')
|
||||
orderbook = get_orderbook(settlement_currency)
|
||||
make_trade(orderbook, payload)
|
||||
|
||||
else:
|
||||
print(f'Not converting {asset} since it is already in the settlement currency')
|
||||
|
||||
while 1:
|
||||
for asset in ['XBT', 'LTC', 'XMR']:
|
||||
@@ -55,5 +84,5 @@ while 1:
|
||||
print(util.get_time(), f'Error attempting to sell {asset}:')
|
||||
print(traceback.format_exc())
|
||||
|
||||
delay = random.randint(30, 90)
|
||||
time.sleep(delay)
|
||||
delay = random.uniform(30, 90)
|
||||
time.sleep(round(delay, 2))
|
||||
|
||||
@@ -24,6 +24,7 @@ KRAKEN_API_SECRET = os.getenv('KRAKEN_API_SECRET', '')
|
||||
|
||||
MAX_NETWORK_FEE_PERCENT = float(os.getenv('MAX_NETWORK_FEE_PERCENT', '5'))
|
||||
MAX_SLIPPAGE_PERCENT = float(os.getenv('MAX_SLIPPAGE_PERCENT', '0.5'))
|
||||
SETTLEMENT_CURRENCY = os.getenv('SETTLEMENT_CURRENCY', 'USD')
|
||||
|
||||
BITCOIN_FEE_SOURCE = os.getenv('BITCOIN_FEE_SOURCE', 'https://mempool.space/api/v1/fees/recommended')
|
||||
BITCOIN_FEE_RATE = os.getenv('BITCOIN_FEE_RATE', 'halfHourFee')
|
||||
|
||||
Reference in New Issue
Block a user