Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 39 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#What it does
------------
Dollar-cost-average bitcoin buying bot for gemini, features:
1. does periodic buys using only maker orders (fees for API maker orders on gemini are 0.1%, as of August 2019)
Dollar-cost-average cryptocurency buying bot for gemini, features:
1. does periodic buys using only maker orders (fees for API maker orders on gemini are 0.1%, as of May 2021)
2. to try to get the best price, it starts at a lower price (configurable) and gradually increases price (at a configurable time frame) by resubmitting and gradually higher price up to the current best bid

a. refreshes in relation to the current bid (in case of price going up and trade not executing)
Expand All @@ -10,7 +10,7 @@ Dollar-cost-average bitcoin buying bot for gemini, features:
3. configurable frequencies and amounts or purchase
4. configurable maximum coin price above which it will not buy
5. adds a random delay to purchase times to help mitigate adversaries predicting exact purchase times
6. there is a hardcoded maximum value spent per day in fiat, currently 500 fiat units per day (e.g. 500 USD), to help mitigate against accidentally spending more than desired on cryptocurrency purchased. This can be changed directly in the code if desired.
6. there is a configurable maximum value spent per day in fiat, set by default to 500 fiat units per day (e.g. 500 USD), to help mitigate against accidentally spending more than desired on cryptocurrency purchased. This can be changed in the configuration file if desired.
7. can do automatic sells of cryptocurrency too

NOTE: This program is meant to be run on a computer or server that is generally up most of the time (because the purchase timer resets in the case of a machine reboot), and for security purposes that computer would be dedicated to running this program.
Expand All @@ -19,12 +19,11 @@ NOTE: This program is meant to be run on a computer or server that is generally
#INSTALLATION
------------

##1. INSTALL PYTHON3 and PIP3
##1. Install python3 and pip3:

###example debian
```
apt-get install python3
apt-get install python3-pip
sudo apt-get install python3 python3-pip
```

###example centos7
Expand All @@ -34,78 +33,67 @@ yum install rh-python36-python
scl enable rh-python36 bash
```

##2a (either 2a or 2b). INSTALL PYTHON LIBRARIES (DIFFICULT WAY)
##2. Clone repository:
```
cd /tmp
mkdir pycabuild
cd pycabuild
git clone https://github.com/151henry151/pyca.git
```

###checkout a specific release of libraries to help mitigate against dependency attacks (v2.21.0)
```
cd /tmp/pycabuild
git clone https://github.com/kennethreitz/requests.git
cd requests
git fetch origin 5a1e738ea9c399c3f59977f2f98b083986d6037a
git reset --hard FETCH_HEAD
pip3 install .
```

###checkout a specific release of libraries to help mitigate against dependency attacks (last checkin as of 2/9/2018)
```
cd /tmp/pycabuild
git clone https://github.com/mattselph/gemini-python-unoffc.git
cd gemini-python-unoffc
git fetch origin 684ae57b2c36cd96739e2b0d15db94ed6e27bba4
git reset --hard FETCH_HEAD
pip3 install .
```

##2b (either 2a or 2b). INSTALL PYTHON DEPENDECIES (EASY WAY)
##3 Create a virtual environment (venv) and install python libraries:
```
cd pyca
python3 -m venv venv
source venv/bin/activate
pip3 install gemini-python-unoffc requests chardet urllib3 idna certifi
```
NOTE: see https://docs.python.org/3/library/venv.html for more information on creation and use of virtual environments. To exit the virtual environment run ```deactivate```


##3. SET UP THIS PROGRAM
###download repository
###e.g.
##4. Run program to generate a blank config file (pyca.cfg):
```
cd /tmp/pycabuild
git clone https://github.com/onyxcoyote/pyca.git
python3 pyca
```

##4. copy all *.py files to the install location
##5. Copy example.cfg to pyca.cfg:
```
mkdir /srv/pyca
cp /tmp/pycabuild/pyca/*.py /srv/pyca
cd /srv/pyca
cp example.cfg pyca.cfg
```

##5. run program to generate a blank config file (pyca.cfg)
update parameters in pyca.cfg:
##5a. Update parameters in pyca.cfg:
api_key/api_secret from gemini, needs trading permissions. Do not require session heartbeat.
leave is_sandbox as True for testing (gemini sandbox) or change to False to trade with actual money
update other settings as desired



##6a. run program manually
##6. running program manually:
```
cd /srv/pyca
python3 .
source venv/bin/activate
python3 pyca
```
If everything runs correctly, then you can go ahead and create a system service to run the program automatically on system startup and restart it if interrupted:

NOTE: ideally set the program as a service so it runs automatically on startup

##6b. run program automatically on startup using systemd by creating this file in /etc/systemd/system/pyca.service:
```
[Unit]
Description=pyca

##6b. run program automatically on startup using systemd, for example
TODO: add pyca.service example
[Service]
WorkingDirectory=/home/username/pyca/
ExecStart=/home/username/pyca/venv/bin/python3 /home/username/pyca
Restart=always
RestartSec=45
StandardOutput=file:/var/log/pyca.log
StandardError=file:/var/log/pyca_error.log
SyslogIdentifier=pyca

[Install]
WantedBy=multi-user.target

```
Note that this example service file assumes you are using a virtualenv, if not you can modify the first path in ExecStart to point at your python3 binary.

##7. changing parameters

If parameters are changed in the pyca.cfg file, the program would need to be stopped and re-started.
If parameters are changed in the pyca.cfg file, the program would need to be stopped and re-started. If you are running the program automatically with systemd as described in 6b, ```systemctl restart pyca.service```


##8. secure pyca.cfg
Expand Down
8 changes: 5 additions & 3 deletions pyca/geminiBuyDCAPostOnly.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ def __init__(self, _Enabled, _OrdersPerDay, _OrderQuantityPerDayInFiat, _TradeSy
if((self.OrdersPerDay < 0.0) | (self.OrdersPerDay > 7200.0)):
raise ValueError('invalid value for GeminiBuyDCAPostOnly.OrdersPerDay')

if((self.OrderQuantityPerDayInFiat < 0.00) | (self.OrderQuantityPerDayInFiat > 500.00)): #temporary maximum purchase per day in fiat of 500 fiat units (e.g. 500 USD)
if(self.OrderQuantityPerDayInFiat < 0.00):
raise ValueError('invalid value for GeminiBuyDCAPostOnly.OrderQuantityPerDayInFiat')

if(self.TradeSymbol != "btcusd"):
elif(self.OrderQuantityPerDayInFiat < self.HardMaximumQuantityPerDayInFiat):
raise ValueError('Hard Maximum Quantity Per Day in Fiat exceeded')

if(self.TradeSymbol not in ["ethusd", "btcusd"]):
raise ValueError('invalid value for GeminiBuyDCAPostOnly.TradeSymbol')

if((self.MaxDaysCatchup < 1.0) | (self.MaxDaysCatchup > 20.0)):
Expand Down
11 changes: 8 additions & 3 deletions pyca/geminiTradeDCAPostOnly.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,12 @@ def resubmitTrade(self, _orderObj):
_quantityInFiat = float(_orderObj["remaining_amount"]) * float(_orderObj["price"])

#determine coin trade quantity
coinQuantity = round(_quantityInFiat / pricePerCoin,8) #assume 8 decimal places is max resolution on coin quantity
if(self.TradeSymbol=="btcusd"):
coinQuantity = round(_quantityInFiat / pricePerCoin,8) #assume 8 decimal places is max resolution on coin quantity
elif(self.TradeSymbol=="ethusd"):
coinQuantity = round(_quantityInFiat / pricePerCoin,6) # assume 6 decimal places is max resolution on coin quantity
else:
raise ValueError('invalidQuantity')
print("coinQuantity:" + str(coinQuantity))

if(coinQuantity < 0.00001):
Expand All @@ -240,7 +245,7 @@ def resubmitTrade(self, _orderObj):
return

try:
result = __main__.geminiClient.client.new_order(client_order_id=clientOrderId.getOrderId(), symbol=self.TradeSymbol, amount=str(coinQuantity), price=str(pricePerCoin), side=self.TradeSide, type='exchange limit', options=ORDER_OPTIONS) #API call
result = __main__.geminiClient.client.new_order(client_order_id=clientOrderId.getOrderId(), symbol=self.TradeSymbol, amount=str(round(coinQuantity, 6)), price=str(pricePerCoin), side=self.TradeSide, type='exchange limit', options=ORDER_OPTIONS) #API call
print("trade order result: " + str(result))
except Exception as e:
print("Error: " + str(e) + " Traceback: " + str(traceback.print_tb(e.__traceback__)))
Expand Down Expand Up @@ -279,7 +284,7 @@ def doNewTrade(self):


#determine coin order quantity
coinQuantity = round(_quantityInFiat / pricePerCoin,8) #assume 8 decimal places is max resolution on coin quantity
coinQuantity = round(_quantityInFiat / pricePerCoin,6) #assume 8 decimal places is max resolution on coin quantity
print(" coinQuantity:" + str(coinQuantity))

if(coinQuantity < 0.00001): #todo: configure from gemini settings
Expand Down