Skip to content

Commit

Permalink
Merge pull request #41 from theimo1221/Combine
Browse files Browse the repository at this point in the history
Combined Pull Request for many updates #35-#38 and 40.
  • Loading branch information
pmaji committed Feb 18, 2018
2 parents 3dae9e0 + 120d0c3 commit 3d9352a
Showing 1 changed file with 76 additions and 46 deletions.
122 changes: 76 additions & 46 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,24 @@

SYMBOLS = {"USD": "$", "BTC": "₿", "EUR": "€", "GBP": "£"}
THRESHOLDS = {"ETH": 1.0, "BTC": 0.25, "LTC": 4.0}
TICKERS = ("ETH-USD", "ETH-BTC", "BTC-USD", "LTC-USD")

TICKERS = ("ETH-USD", "ETH-BTC", "BTC-USD", "LTC-USD", "LTC-BTC", "ETH-EUR", "BTC-EUR", "LTC-EUR")
GRAPH_IDS = ['live-graph-' + ticker.lower().replace('-', '') for ticker in TICKERS]
TBL_PRICE = 'price'
TBL_VOLUME = 'volume'
tables = {}
sendCache = {}


# creates a cache to speed up load time and facilitate refreshes
def get_data_cache(ticker):
return tables[ticker]

def get_All_data():
return tables

def getSendCache():
return sendCache

public_client = gdax.PublicClient() # defines public client for all functions; taken from GDAX

Expand All @@ -42,7 +49,9 @@ def get_data_cache(ticker):
# threshold is to limit our view to only orders greater than or equal to the threshold size defined
# uniqueBorder is the border at wich orders are marked differently
# range is the deviation visible from current price
def get_data(ticker, threshold=1.0, uniqueBorder=5, range=0.025):

def get_data(ticker, threshold=1.0, uniqueBorder=5, range=0.05, maxSize=32, minVolumePerc=0.01):
global tables
# Determine what currencies we're working with to make the tool tip more dynamic.
currency = ticker.split("-")[0]
base_currency = ticker.split("-")[1]
Expand Down Expand Up @@ -82,13 +91,25 @@ def get_data(ticker, threshold=1.0, uniqueBorder=5, range=0.025):

# transforms the table for a final time to craft the data view we need for analysis
final_tbl = fulltbl.groupby([TBL_PRICE])[[TBL_VOLUME]].sum()


#Filter to just use data > Minimal Volume Percent
minVolume=final_tbl[TBL_VOLUME].sum() * minVolumePerc
final_tbl = final_tbl[(final_tbl[TBL_VOLUME] >= minVolume)]

final_tbl['n_unique_orders'] = fulltbl.groupby(TBL_PRICE).address.nunique().astype(float)
final_tbl[TBL_PRICE] = final_tbl.index
final_tbl[TBL_PRICE] = final_tbl[TBL_PRICE].apply(round_sig, args=(3, 0, 2))
final_tbl[TBL_VOLUME] = final_tbl[TBL_VOLUME].apply(round_sig, args=(1, 2))
final_tbl['n_unique_orders'] = final_tbl['n_unique_orders'].apply(round_sig, args=(0,))
# print(final_tbl)
final_tbl['sqrt'] = np.sqrt(final_tbl[TBL_VOLUME])

# Fixing Bubble Size
cMaxSize = final_tbl['sqrt'].max()
sizeFactor = maxSize/cMaxSize
final_tbl['sqrt'] = final_tbl['sqrt'] * sizeFactor

# making the tooltip column for our charts
final_tbl['text'] = (
"There are " + final_tbl[TBL_VOLUME].map(str) + " " + currency + " available for " + symbol + final_tbl[
Expand All @@ -102,24 +123,16 @@ def get_data(ticker, threshold=1.0, uniqueBorder=5, range=0.025):
final_tbl['market price'] = final_tbl['market price'].astype(float)

# determine buys / sells relative to last market price; colors price bubbles based on size
# buys are green (with default uniqueBorder if there are 5 or more unique orders at a price, the color is bright, else dark)
# sells are red (with default uniqueBorder if there are 5 or more unique orders at a price, the color is bright, else dark)
# color map can be found at : https://matplotlib.org/examples/color/named_colors.html

final_tbl.loc[((final_tbl[TBL_PRICE] > final_tbl['market price']) & (
final_tbl['n_unique_orders'] >= uniqueBorder)), 'color'] = \
'red'
final_tbl.loc[
((final_tbl[TBL_PRICE] > final_tbl['market price']) & (final_tbl['n_unique_orders'] < uniqueBorder)), 'color'] = \
'darkred'
final_tbl.loc[((final_tbl[TBL_PRICE] <= final_tbl['market price']) & (
final_tbl['n_unique_orders'] >= uniqueBorder)), 'color'] = \
'lime'
final_tbl.loc[((final_tbl[TBL_PRICE] <= final_tbl['market price']) & (
final_tbl['n_unique_orders'] < uniqueBorder)), 'color'] = \
'green'
# Buys are green, Sells are Red. Phishy ones are highlighted by beeing bright, detected by unqiue orders.
marketPrice=final_tbl['market price']
final_tbl['colorintensity']=final_tbl['n_unique_orders'].apply(calcColor)
final_tbl.loc[(final_tbl[TBL_PRICE]>marketPrice),'color']= \
'rgb('+final_tbl.loc[(final_tbl[TBL_PRICE]>marketPrice),'colorintensity'].map(str) +',0,0)'
final_tbl.loc[(final_tbl[TBL_PRICE]<=marketPrice),'color']= \
'rgb(0,'+final_tbl.loc[(final_tbl[TBL_PRICE]<=marketPrice),'colorintensity'].map(str) +',0)'

tables[ticker] = final_tbl
tables[ticker] = prepare_data(ticker)
return tables[ticker]


Expand All @@ -134,18 +147,19 @@ def refreshWorker():


def refreshTickers():
global sendCache
for ticker in TICKERS:
currency = ticker.split("-")[0]
thresh = THRESHOLDS.get(currency.upper(), 1.0)
get_data(ticker, thresh)
sendCache=prepare_send()


# begin building the dash itself
app = dash.Dash()

# simple layout that can be improved with better CSS later, but it does the job for now

div_container = [
static_content_before = [
html.H2('CRYPTO WHALE WATCHING APP'),
html.H3('Donations greatly appreciated; will go towards hosting / development'),
html.P(['ETH Donations Address: 0xDB63E1e60e644cE55563fB62f9F2Fc97B751bc49', html.Br(),
Expand All @@ -158,18 +172,21 @@ def refreshTickers():
html.A(html.Button('Freeze all'),
href="javascript:var k = setTimeout(function() {for (var i = k; i > 0; i--){ clearInterval(i)}},1);"),
html.A(html.Button('Un-freeze all'), href="javascript:location.reload();")
]
for graphId in GRAPH_IDS:
div_container.append(dcc.Graph(id=graphId))
]

div_container.append(dcc.Interval(
id='interval-component',
interval=4 * 1000 # in milliseconds for the automatic refresh; refreshes every 4 seconds
))
app.layout = html.Div(div_container)

static_content_after=dcc.Interval(
id='main-interval-component',
interval=2 * 1000 # in milliseconds for the automatic refresh; refreshes every 2 seconds
)
app.layout = html.Div(id='main_container',children=[
html.Div(static_content_before),
html.Div(id='graphs_Container'),
html.Div(static_content_after),
])

def update_data(ticker):

def prepare_data(ticker):
data = get_data_cache(ticker)
base_currency = ticker.split("-")[1]
symbol = SYMBOLS.get(base_currency.upper(), "")
Expand All @@ -180,7 +197,7 @@ def update_data(ticker):
y=data[TBL_PRICE],
mode='markers',
text=data['text'],
opacity=0.7,
opacity=0.95,
hoverinfo='text',
marker={
'size': data['sqrt'],
Expand All @@ -193,31 +210,38 @@ def update_data(ticker):
'layout': go.Layout(
# makes it so that title automatically updates with refreshed market price
title=("The present market price of {} is: {}{}".format(ticker, symbol, str(data['market price'].iloc[0]))),
xaxis={'title': 'Order Size'},
xaxis=dict(
title='Order Size',
type='log',
autorange=True
),
yaxis={'title': '{} Price'.format(ticker)},
hovermode='closest'
)
}
return result

def prepare_send():
lCache = []
cData=get_All_data()
for ticker in TICKERS:
graph= 'live-graph-' + ticker.lower().replace('-', '')
lCache.append(html.Br())
lCache.append(html.Br())
lCache.append(html.A(html.Button('Hide/ Show '+ticker),
href='javascript:(function(){if(document.getElementById("'+graph+'").style.display==""){document.getElementById("'+graph+'").style.display="none"}else{document.getElementById("'+graph+'").style.display=""}})()'))
lCache.append(dcc.Graph(
id=graph,
figure=cData[ticker]
))
return lCache

# links up the chart creation to the interval for an auto-refresh
# creates one callback per currency pairing; easy to replicate / add new pairs

# Function generator
def create_cb_func(pGraph):
def cb():
return update_data(pGraph)

return cb


# Loop through graphs and append callback
for ticker in TICKERS:
graph = 'live-graph-' + ticker.lower().replace('-', '')
app.callback(Output(graph, 'figure'),
events=[Event('interval-component', 'interval')])(create_cb_func(ticker))

@app.callback(Output('graphs_Container', 'children'),
events=[Event('main-interval-component', 'interval')])
def update_Site_data():
return getSendCache()

def round_sig(x, sig=3, overwrite=0, minimum=0):
if (x == 0):
Expand All @@ -232,6 +256,12 @@ def round_sig(x, sig=3, overwrite=0, minimum=0):
return round(x, digits)


def calcColor(x):
response=round(400/x)
if response>255 : response=255
elif response<30 : response=30
return response

if __name__ == '__main__':
refreshTickers()
t = threading.Thread(target=refreshWorker)
Expand Down

0 comments on commit 3d9352a

Please sign in to comment.