Employ an AI to build your Social Analysis Bot for the crypto market

Dmytro Sazonov
𝐀𝐈 𝐦𝐨𝐧𝐤𝐬.𝐢𝐨
11 min readDec 8, 2023

Discover how to leverage AI components like Chat GPT, NLTK, and algorithmic analysis to create your own Analytical Discord Bot for measuring people sentiments and social trends on the crypto market.

Photo by Agence Olloweb on Unsplash

“Sometimes it is the people who no one imagines anything of who do the things that no one can imagine.”

Alan Turing

You’ve probably heard about the latest Open AI release of Chat GPT and its amazing new feature, GPTs, which brings us to the next level of building user experiences based on AI conversational chatbots. Yes, it has already been realized and is available in a paid subscription. However, we are not gonna delve into those new amazing features in this article. Instead, we will take a more conservative approach to analyze Big Data for measuring people sentiments and social trends on the crypto market.

ADVERTISEMENT: If you or someone you know is interested in collaborating with an expert in AI and Chatbot development, my friends from cosmith.io offer top-notch services for Chat GPT development and integrations.

This article is the logical continuation of my research and development initiative - Whale Indicator. The initial idea and theoretical base described in article Let’s copy the “BlackRock approach” to trade profitably on the crypto market. Chat GPT is gonna be employed to summarize analysis results at the end.

What will we build?

We are going to build a comprehensive Analytical Bot that uses Discord webhook to send messages and images to the Discord channel after it’s being created during the analysis process. This analysis should help investors to assess people’s sentiments and social trends regarding particular crypto asset to make investment decisions more accurate and informed.

Prerequisites

To turn this into reality and achieve our objectives, we need to acquire three things before starting the coding process:

  • Signup and obtain the API key on Crypto Compare Big Data provider. We need it to download Data about Twitter followers, Latest news and crypto asset prices which we will use to analyze;
  • Create the Discord channel and Webhook in your Discord Server using their UI. We will need this as a place where the entire analysis will appear when ready;
  • Create your Open AI API key using the Open AI Platform. We will employ Chat GPT Summarization function to make user-friendly summary at the end of the analysis process.

Tools and libraries

  • Python
  • Google Collaboratory (Colab)
  • discordwebhook
  • openai
  • NLTK
  • matplotlib
  • mplfinance

Install packages

It is essential to install the required packages outlined below. These packages are crucial for retrieving information from the Big Data Provider, in our case, CryptoCompare, conducting analysis, generating images, and sending messages to Discord.

!pip install discordwebhook
!pip install openai==0.27.8
!pip install nltk

!pip install mplfinance

If you have successfully installed all the necessary packages, the next step is to declare their usage as shown below.

import io
import uuid
import random
import pandas as pd
import datetime as dt
import requests as rq

import matplotlib.dates as mdates
import matplotlib.ticker as mticker
import matplotlib.pyplot as plt

import openai
import nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
nltk.download('vader_lexicon')

from mplfinance.original_flavor import candlestick_ohlc
from discordwebhook import Discord

Please be aware that we additionally use the pandas, random, and uuid packages. While these packages are typically available in Google Colab, you may need to install some of them if you are using GCP.

Setup API KEYs

As mentioned in the ‘Prerequisites’ section, it is crucial to set up all the necessary API KEYs, as listed in the code below. Ensure that you retrieve these keys from the appropriate providers.

# SETTINGS
openai.api_key = '[OPENAI_API_KEY]'
BIG_DATA_PROVIDER_URL = 'https://min-api.cryptocompare.com'
BIG_DATA_PROVIDER_API_KEY = '[CRYPTO_COMPARE_API_KEY]'
WEBHOOK_URL = '[DISCORD_WEBHOOK_URL]'

symbols = [{'coin':'BTC', 'id':'1182'},
{'coin':'ETH', 'id':'7605'},
{'coin':'XRP', 'id':'5031'},

{'coin':'ADA', 'id':'321992'},
{'coin':'LINK', 'id':'309621'},

{'coin':'ETC', 'id':'5324'},
{'coin':'SOL', 'id':'934443'},
{'coin':'ATOM', 'id':'199107'},
]

symbol_pair = 'USDT'
  • [OPENAI_API_KEY] should be replaced with the API key from the Open AI platform;
  • [DISCORD_WEBHOOK_URL] should be substituted with the appropriate URL retrieved from your Discord server;
  • [CRYPTO_COMPARE_API_KEY] should be updated to the actual API key from the Big Data Provider you intended to use in your algorithm.

As you may see from the above code, we will generate and provide our analysis for the list of crypto assets listed in the array ‘symbols’.

Discord Webhook

As we agreed to use a Discord channel for hosting our analysis results, we will send messages to the Discord Server using a Discord webhook.

discord = Discord(url=WEBHOOK_URL)

def send_message(message, plot):
discord = Discord(url=WEBHOOK_URL)
image_stream = io.BytesIO()
plot.savefig(image_stream, format='png')
image_stream.seek(0)
plt.close()

image_file = {
'file': (f'{str(uuid.uuid4())}.png', image_stream, 'image/png')
}

discord.post(content=message, file=image_file)

def send_single_message(message):
discord = Discord(url=WEBHOOK_URL)
discord.post(content=message)

As demonstrated above, we have a few functions that assist us in sending messages to Discord:

  • send_message(message, plot) — uses to send message with image;
  • send_single_message(message) — uses to send just text messages.

Both functions use global object ‘discord’ which is based on the class Discord from discordwebhook package.

Chat GPT’s function

As part of this code, we use Chat GPT for just one purpose — summarization. Once the Analysis is complete, we generate a user-friendly summary based on the Analysis text. We retrieve this summary from Chat GPT using the basic model ‘gpt-3.5-turbo’ and a single ChatCompletion object from the ‘openai’ package, as shown below.

def get_openai_answer(user_input):
user_msg = {
'role': 'user',
'content': f'{user_input}' }
return openai.ChatCompletion.create(
model="gpt-3.5-turbo",
temperature=0.4,
top_p=1,
messages=[user_msg])

In the context of the ChatCompletion class from the Open AI package, the provided values temperature=0.4 and top_p=1 indicate that a relatively low temperature is used (0.4), which makes the output more focused, and top_p is set to 1, meaning it includes all tokens without further filtering based on probability. These settings suggest a more deterministic and focused message generation.

For more details on leveraging Open AI functionality to construct conversational chatbots, read an another article ‘Build Your Own Conversational Chatbot Using ChatGPT API’.

Big Data Provider’s functions

My intention is to leverage pre-existing Big Data related to certain crypto asset. We will get prices, Twitter followers associated with coin, and the latest news. We can do this using the Big Data Provider to reduce costs on gathering information. Be aware, beyond this service, there an extensive infrastructure dedicated to collecting data for us.

def get_prices_for_coinpair(coin1, coin2, limit):
result = \
rq.get(f'{BIG_DATA_PROVIDER_URL}/data/v2/histoday?fsym=' + \
'{coin1}&tsym={coin2}&limit={limit}&api_key={BIG_DATA_PROVIDER_API_KEY}')
if result.ok:
return result.json()
else:
return {}

def get_social_data(coin, limit):
coinId = [x["id"] for x in symbols if x["coin"] == coin][0]
result = \
rq.get(f'{BIG_DATA_PROVIDER_URL}/data/social/coin/histo/day?coinId=' + \
'{coinId}&limit={limit}&api_key={BIG_DATA_PROVIDER_API_KEY}')
if result.ok:
return result.json()
else:
return {}

def get_news_for_coin(coin):
result = \
rq.get(f'{BIG_DATA_PROVIDER_URL}/data/v2/news/?lang=EN&categories=' + \
'{coin}&api_key={BIG_DATA_PROVIDER_API_KEY}')
if result.ok:
return result.json()
else:
return {}

We will be using just three functions from the Big Data Provider:

  • get_prices_for_coinpair(coin1, coin2, limit) — utilizes to fetch prices for a specific crypto asset ‘coin1’ in relation to another one ‘coin2’ over the limited timeframe of ‘limit’ days;
  • get_social_data(coin, limit) — employs to retrieve information regarding the number of Twitter and Reddit followers associated with a specific crypto asset ‘coin’ over a limited timeframe of ‘limit’ days;
  • get_news_for_coin(coin) — retrieves the latest 50 news specific to the crypto asset ‘coin’.

CryptoCompare has restrictions on the number of messages you can retrieve per month, with a limit set to 100,000 calls in the ‘FREE PLAN’.

Sentiment analysis

NLTK stands as the leading platform for developing Python applications focused on Natural Language Processing tasks. We’ll utilize the Sentiment Intensity Analyzer to identify the sentiments expressed in news specific to certain crypto asset.

Using the score[‘compound’], we will calculate the distribution of POSITIVE, NEGATIVE, or NEUTRAL sentiments in the news fetched from Data Provider for a specific crypto asset.

# SENTIMENT ANALYSIS
def news_analysis(news):
sentiment = {}

negative = []
positive = []
neutral = []

for item in news:
score = SentimentIntensityAnalyzer().polarity_scores(item['body'])
compound = score['compound']
if compound >= 0.05:
positive.append(item)
elif compound <= -0.05:
negative.append(item)
elif compound > -0.05 and compound < 0.05:
neutral.append(item)

if len(positive) > len(negative):
sentiment_str = 'POSITIVE'
elif len(negative) > len(positive):
sentiment_str = 'NEGATIVE'
else:
sentiment_str = 'NA'

sentiment = {'sentiment': sentiment_str, 'url' : \
positive[0]['url'] if sentiment_str == 'POSITIVE' \
else negative[0]['url'] if sentiment_str == 'NEGATIVE' \
else neutral[0]['url'], \
'positive': len(positive), \
'negative': len(negative), \
'neutral': len(neutral)}

return sentiment

We classify news as POSITIVE if the value is greater than or equal to 0.05.
If the value is less than or equal to -0.05, we categorize the news as NEGATIVE. For values falling between -0.05 and 0.05, we label them as NEUTRAL news.

To determine the SENTIMENT for the crypto asset, we employ the following logic:

  • POSITIVE: If the number of positive news exceeds the number of negative ones;
  • NEGATIVE: If the number of negative news articles surpasses the number of positive ones;
  • NEUTRAL: If the sum of positive and negative news is equal.

Very similar sentiment-determining logic was used in another work, which you can explore in the article ‘AI predicts stock market using Twitter’.

Image generation

I intend to use both ‘mplfinance.candlestick_ohlc’ and ‘matplotlib.pyplot’ for image generation in this work. The key difference is in use ‘candlestick_ohlc’ for more financially reliable candle sticks.

def get_prices_df(prices):
prices_df = pd.DataFrame(prices['Data']['Data'])

prices_df['Date'] = pd.to_datetime(prices_df['time'], unit='s')
prices_df['Date'] = prices_df['Date'].apply(mdates.date2num)

data = {'Date': prices_df['Date'].to_list(),
'Open': prices_df['open'].to_list(),
'High': prices_df['high'].to_list(),
'Low': prices_df['low'].to_list(),
'Close': prices_df['close'].to_list(),
'Volume': prices_df['volumefrom'].to_list()}

prices_df = pd.DataFrame(data)
return prices_df

# IMAGE GENERATION
def get_social_analysis(symbol, symbol_pair, prices_df, social_data):
fig = plt.figure(figsize=(10, 6))
ax1 = plt.subplot2grid((5,1), (0,0), colspan=1, rowspan=3)

candlestick_ohlc(ax1, prices_df.values, width=0.5, \
colorup='#00b359',colordown='#ff8080', alpha=1)

ax1.set_ylabel(f'Price, {symbol_pair}')
ax1.set_xticks([])
plt.title(f'{symbol} Prices and Twitter followers Correlation')

ax2 = plt.subplot2grid((5,1), (3,0), colspan=1, rowspan=2, frameon=False)
ax2.plot([dt.datetime.fromtimestamp(b[1]) for b in social_data],\
[(b[0]/1_000_000) for b in social_data],linewidth=2, color='#11b9ff')
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax2.xaxis.set_major_locator(mticker.MaxNLocator(9))
ax2.grid()
ax2.set_xlabel('Date')
ax2.legend(['Twitter followers, mln.'], loc='upper left')

# plt.show()
return plt

Function get_prices_df(prices) is intended to prepare data for ‘candlestick_ohlc’; The same time another function get_social_analysis(symbol, symbol_pair, prices_df, social_data) uses to generate image for the analysis. This image includes information for coin ‘symbol’ prices and graphic of Twitter followers correlation.

If you are experimenting in Google Colab you can uncomment line with
# plt.show()’ to display graphic for debug purposes.

Bot’s main function

You have to run this function to start comprehensive analysis on crypto asset, incorporating price trends, social media metrics, sentiment analysis on news, and summarization using Open AI package.

To do that just run the following code.

whale_analyst_go({})

If you are using Google Colab, you simply need to execute this line. However, if you are opting for GCP function, you can configure the scheduler to trigger the web function at a specified schedule.

# Main function
def whale_analyst_go(request):
symbol = symbols[random.randrange(0, len(symbols)-1, 1)]['coin']
block_data_count = random.randrange(19, 28, 1)
block_local_count = random.randrange(3, 7, 1)

prices = get_prices_for_coinpair(symbol,symbol_pair,block_data_count)
prices_data = [(x['close'], \
x['time']) for x in prices['Data']['Data']][:block_data_count]

social = get_social_data(symbol, len(prices_data))
social_data = [(x['twitter_followers'], \
x['time']) for x in social['Data']][:len(prices_data)]

# Calculations
last_price = prices_data[len(prices_data)-1][0]
first_price = prices_data[0][0]
trend_price_condition = abs(last_price / first_price)
trend_price = \
'UP' if trend_price_condition > 1 else \
'DOWN' if trend_price_condition < 0.8 else 'FLAT'

price_percent_change = \
"{:.2f}".format((last_price-first_price) / (first_price * 0.01))

local_price = prices_data[len(prices_data)-block_local_count][0]
trend_local_price_condition = abs(last_price / local_price)
trend_local_price = \
'UP' if trend_local_price_condition > 1 else \
'DOWN' if trend_local_price_condition < 0.8 else 'FLAT'

local_price_percent_change = \
round((last_price-local_price) / (local_price * 0.01),2)

last_social = social_data[len(social_data)-1][0]
first_social = social_data[0][0]
trend_social_condition = abs(last_social / first_social)
trend_social = \
'UP' if trend_social_condition > 1 else \
'DOWN' if trend_social_condition < 0.8 else 'FLAT'

social_percent_change = "{:.0f}" \
.format((last_social-first_social) / (first_social * 0.01))

local_message = ''
if trend_local_price != trend_price and abs(local_price_percent_change) > 0.01:
local_message = \
f"\nHowever, there is a change in the recent price movement for" + \
f" the last {block_local_count} days. Price changed from " + \
f"*{local_price} {symbol_pair}* to *{last_price} {symbol_pair}*" + \
f"({local_price_percent_change}%)." \

# Message generation
message = f"Current price for **{symbol}** is **" + \
f"{'increasing' if trend_price == 'UP' else 'decreasing' if trend_price == 'DOWN' else 'being consolidated'}**. " + \
f"It has changed from *{first_price} {symbol_pair}* to *{last_price} " + \
f"{symbol_pair}* ({price_percent_change}%) for the last {block_data_count} days." + \
local_message + \
f"\n{'The same time' if trend_social == trend_price else 'Meanwhile'} " + \
f"the amount of Twitter followers is **" + \
f"{'growing' if trend_social == 'UP' else 'decreasing' if trend_social == 'DOWN' else 'not changing much'}**. " + \
f"{block_data_count} days ago it was {'{:,}'.format(first_social)} followers, changed to {'{:,}'.format(last_social)} followers" + \
f"{f', {social_percent_change}% change' if abs(float(social_percent_change)) > 0.01 else ''}."

prices_df = get_prices_df(prices)
send_message(message, \
get_social_analysis(symbol, symbol_pair, prices_df, social_data))

news = get_news_for_coin(symbol)
sentiment = news_analysis(news['Data'])
if sentiment != {}:
send_single_message(f"__Sentiment analysis__: negative = \
*{sentiment['negative']}*, \
positive = *{sentiment['positive']}*, neutral = *{sentiment['neutral']}*, \
sentiment = **{sentiment['sentiment']}**")
send_single_message(f"[Read latest news]({sentiment['url']})")

res = \
get_openai_answer('summarize in 1 paragraph, maximum 300 symbols' + \
' with recommendation where to buy, hold or sell with no recomendations' + \
' about social media [' + message + ']')
if res:
generated_msg = res["choices"][0]["message"]["content"].strip().replace('"', '')
send_single_message(f"```SUMMARY: {generated_msg}```")

return 'Whale analyst: DONE!'

As you can see from the provided code, we perform the following:

  • randomly select a crypto asset symbol from the list;
  • retrieve prices and social media data for the selected crypto asset;
  • determine trends and changes;
  • analyze recent local price movements and construct messages;
  • generate a comprehensive message summarizing price trends, local movements, and Twitter followers changes;
  • analyze news related to the crypto asset to determine its sentiment;
  • request summarization from the Open AI API;
  • send messages to the appropriate Discord channel.

Now that the full code is understood, I believe we can proceed to review the outcomes.

What does it look like?

The complete analytical report for a specific crypto asset comprises five sections, which we will discuss next.

At the forefront, the Algorithmic Analysis Summary presents key information regarding price movement in percentage and changes in Twitter followers in percentage as well.

Current price for LINK is increasing. It has changed from 11.5 USDT to 14.41 USDT (25.30%) for the last 27 days.
The same time the amount of Twitter followers is
growing. 27 days ago it was 1,045,979 followers, changed to 1,064,878 followers, 2% change.

Following that, there is an image displaying asset prices and their correlation with the change in Twitter followers over the time.

LINK prices and Twitter followers correlation

Then, just a short representation of the Sentiment Analysis results based on last 50 news about the crypto asset. In our case it’s LINK.

Sentiment analysis: negative = 3, positive = 40, neutral = 7,
sentiment = POSITIVE

Next, we have the ‘Latest News’ section, where the most recent and relevant news is displayed.

‘Latest news’ section of analysis

At the end, as described earlier, we have the Summary section, which is generated by the Chat GPT Summarization function.

SUMMARY: The current price for LINK has been increasing significantly, 
rising from 11.5 USDT to 14.41 USDT in the last 27 days, representing
a 25.30% increase. Additionally, the number of Twitter followers for
LINK has also been growing, with a 2% increase from 1,045,979 followers
to 1,064,878 followers. Based on these trends, it may be a good time to
consider buying or holding LINK as it shows potential for further growth.
However, it is important to conduct further research and analysis before
making any investment decisions.

The entire analysis for various crypto assets is presented one by one in the #social-analysis channel in Discord as shown on the picture below.

Discord channel #social-analysis in the Whale Indicator

Once ready to review, we navigate to the #social-analysis channel and explore all the data mined by the Discord Bot ‘Whale Analyst’ in our case. Give it your preferred name on your own server.

What is next?

I believe you have enjoyed this article and are now ready to create your own Analytical Bot for Discord server.

Script: Google Colab

What is next? — I have no clue. Something that no one can imagine.
Just stay tuned :)

Get in touch

Feel free to contact me if you have any questions about constructing analytical bots for the crypto market, employing various AI components such as Chat GPT, NLTK, or Discord bot development.

Twitter: https://twitter.com/dmytro_sazonov

Join discussion: https://discord.com/invite/SXRCz8Yzcq

The best expert for Chat GPT development and integrations

--

--

Dmytro Sazonov
𝐀𝐈 𝐦𝐨𝐧𝐤𝐬.𝐢𝐨

Blockchain enthusiast and artificial intelligence researcher. I believe with these tools we will build better tomorrow :)