-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathreddit_crypto_trader.py
196 lines (150 loc) · 6.18 KB
/
reddit_crypto_trader.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
from auth.reddit_auth import *
from trade_client import *
from store_order import *
from datetime import datetime, time
import time
import json
import os.path
import nltk
nltk.download()
from nltk.sentiment import SentimentIntensityAnalyzer
reddit = load_creds('auth/auth.yml')
config = load_config('config.yml')
keywords = load_keywords('keywords.yml')
print(f'logged in as {reddit.user.me()}')
def get_post():
"""
Returns relevant posts based the user configuration
"""
posts = {}
for sub in config['SUBREDDITS']:
subreddit = reddit.subreddit(sub)
relevant_posts = getattr(subreddit, config['SORT_BY'])(limit=config['NUMBER_OF_POSTS'])
for post in relevant_posts:
if not post.stickied:
posts[post.id] = {"title": post.title,
"subreddit": sub,
"body": post.selftext,
}
return posts
def store_posts(data):
"""
Stores relevant posts and associated data in a local json file
"""
with open('reddit_posts.json', 'w') as file:
json.dump(data, file)
def load_posts(file):
"""
Loads saved reddit posts
"""
with open(file, 'r') as f:
return json.load(f)
def compare_posts(fetched, stored):
"""
Checks if there are new posts
"""
i=0
for post in fetched:
if not fetched[post] in [stored[item] for item in stored]:
i+=1
return i
def find_keywords(posts, keywords):
"""
Checks if there are any keywords int he posts we pulled
Bit of a mess but it works
"""
key_posts = {}
for post in posts:
for key in keywords:
for item in keywords[key]:
if item in posts[post]['title'] or item in posts[post]['body']:
key_posts[post] = posts[post]
key_posts[post]['coin'] = key
return key_posts
def analyse_posts(posts):
"""
analyses the sentiment of each post with a keyword
"""
sia = SentimentIntensityAnalyzer()
sentiment = {}
for post in posts:
if posts[post]['coin'] not in sentiment:
sentiment[posts[post]['coin']] = []
sentiment[posts[post]['coin']].append(sia.polarity_scores(posts[post]['title']))
sentiment[posts[post]['coin']].append(sia.polarity_scores(posts[post]['body']))
return sentiment
def get_avg_sentiment(sentiment):
"""
Compiles and returnes the average sentiment
of all titles and bodies of our query
"""
average = {}
for coin in sentiment:
# sum up all compound readings from each title & body associated with the
# coin we detected in keywords
average[coin] = sum([item['compound'] for item in sentiment[coin]])
# get the mean compound sentiment if it's not 0
if average[coin] != 0:
average[coin] = average[coin] / len(sentiment[coin])
return average
def get_price(coin, pairing):
return client.get_ticker(symbol=coin+pairing)['lastPrice']
if __name__ == '__main__':
i = 0
while True:
i +=1
print(f'iteration {i}')
# get the posts from reddit
posts = get_post()
# check if the order file exists and load the current orders
if os.path.isfile('order.json'):
order = load_order('order.json')
else:
order = {}
# check if the reddit posts files exist and load them
if os.path.isfile('reddit_posts.json'):
saved_posts = load_posts('reddit_posts.json')
# this will return the number of new posts we found on reddit
# compared to the ones stored
new_posts = compare_posts(posts, saved_posts)
if new_posts > 0 or i == 2:
print("New posts detected, fetching new posts...")
# store the posts if they are new
store_posts(posts)
# find posts with matching keywords
key_posts = find_keywords(posts, keywords)
# determine the sentiment for each post
sentiment = analyse_posts(key_posts)
# return the compoundavg sentiment, grouped by symbol
analyzed_coins = get_avg_sentiment(sentiment)
print(f'Found matching keywords with the following sentiments: {analyzed_coins}')
for coin in analyzed_coins:
# prepare to buy if the sentiment of each coin is greater than 0
# and the coin hasn't been bought already
if analyzed_coins[coin] > 0 and coin not in order:
print(f'{coin} sentiment is positive: {analyzed_coins[coin]}, preparing to buy...')
price = get_price(coin, config['TRADE_OPTIONS']['PAIRING'])
volume = convert_volume(coin+config['TRADE_OPTIONS']['PAIRING'], config['TRADE_OPTIONS']['QUANTITY'],price)
try:
# Run a test trade if true
if config['TRADE_OPTIONS']['TEST']:
order[coin] = {
'symbol':coin+config['TRADE_OPTIONS']['PAIRING'],
'price':price,
'volume':volume,
'time':datetime.timestamp(datetime.now())
}
print('PLACING TEST ORDER')
else:
order[coin] = create_order(coin+config['TRADE_OPTIONS']['PAIRING'], volume)
except Exception as e:
print(e)
else:
print(f'Order created with {volume} on {coin}')
store_order('order.json', order)
else:
print(f'Sentiment for {coin} is negative or {coin} is currently in portfolio')
time.sleep(config['TRADE_OPTIONS']['RUN_EVERY']*60)
else:
print("Running first iteration, fetching posts...")
store_posts(posts)