igriv commited on
Commit
e958f2a
·
0 Parent(s):

Initial commit

Browse files
Files changed (4) hide show
  1. README.md +11 -0
  2. cryptoindex.py +151 -0
  3. index_interface.py +89 -0
  4. updater.py +25 -0
README.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <<<<<<< HEAD
2
+ # cryptoind
3
+ index for crypto assets
4
+ =======
5
+ ---
6
+ title: crypto_index
7
+ app_file: index_interface.py
8
+ sdk: gradio
9
+ sdk_version: 4.24.0
10
+ ---
11
+ >>>>>>> 99c909b (Initial commit)
cryptoindex.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from polygon import RESTClient
2
+ import pandas as pd
3
+ import numpy as np
4
+ from datetime import datetime, timedelta
5
+
6
+
7
+ def calc_dates(date: datetime = datetime.now()) -> tuple:
8
+ this_year = date - timedelta(days=date.day-1)
9
+ one_year = this_year + timedelta(days=-365)
10
+ return (one_year.strftime("%Y-%m-%d"), this_year.strftime("%Y-%m-%d"))
11
+
12
+
13
+ def do_sharpe(ser, days=True):
14
+ mins_in_year = 60 * 24 * 365
15
+ days_in_year = 365
16
+ if days:
17
+ themean = ser.pct_change().mean() * days_in_year
18
+ thestd = ser.pct_change().std() * np.sqrt(days_in_year)
19
+
20
+ else:
21
+ themean = ser.pct_change().mean() * mins_in_year
22
+ thestd = ser.pct_change().std() * np.sqrt(mins_in_year)
23
+ sharpe = themean/thestd
24
+ return themean, thestd, sharpe, format_output(themean, thestd, sharpe)
25
+
26
+
27
+ def format_output(mymean, mystandarddeviation, mysharpe):
28
+ output = f"""
29
+ | Metric | Value |
30
+ |--------------------|----------------------|
31
+ | Mean | {mymean:.2f} |
32
+ | Standard Deviation | {mystandarddeviation:.2f} |
33
+ | Sharpe-Rivin | {mysharpe:.3f} |
34
+ """
35
+ return output
36
+
37
+ api_key="BBRlVSAOiNqeJ77yjnveFBqZZTOFv2gN"
38
+
39
+ import pandas as pd
40
+ from polygon import RESTClient
41
+ client = RESTClient(api_key)
42
+
43
+ def get_ticker_trade(ticker: str):
44
+ coinname = ticker[2:-3]
45
+ thetrade = client.get_last_crypto_trade(coinname, "USD")
46
+ return thetrade.price
47
+
48
+ def update_df(last_day):
49
+ last_day["price"] = last_day.ticker.map(get_ticker_trade)
50
+ weights = last_day.weight
51
+ return np.average(last_day.price, weights = weights)
52
+
53
+ def get_daily_bars(ticker:str, dete = datetime.now()):
54
+ thedate = dete.strftime("%Y-%m-%d")
55
+ bars = client.get_aggs(ticker=ticker, multiplier=1, timespan="minute", from_= thedate, to=thedate, limit=50000)
56
+ thedf = pd.DataFrame(bars)[['timestamp', "close"]]
57
+ thedf.set_index(pd.to_datetime(thedf.timestamp, unit='ms'), inplace = True)
58
+ thedf.drop("timestamp", axis = 1, inplace = True)
59
+ thedf.rename({"close": ticker}, axis = 1, inplace = True)
60
+ return thedf
61
+
62
+ def update_day(last_day, func =np.sqrt):
63
+ dflist = []
64
+ for ticker in last_day.ticker:
65
+ dflist.append(get_daily_bars(ticker))
66
+ newdf = pd.concat(dflist, axis = 1)
67
+ oldind = newdf.index
68
+ last_day_r = last_day.reset_index(drop=True)
69
+ newdf_r = newdf.reset_index(drop=True)
70
+ close_column = last_day['close']
71
+ #newdf_r = newdf_r.div(close_column, axis=0)
72
+ newdf_r.index = oldind
73
+
74
+ newdf_r["indprice"] = newdf_r.apply(lambda x: np.average(x, weights=func(last_day.weight)), axis = 1)
75
+ return newdf_r.indprice.ffill()
76
+
77
+ etfs = ['VOO','SOXL','TQQQ','LQD','HYG','QQQ', 'IVV','SPY', 'IWM', 'DJI', 'IXIC', 'VIX', 'TLT', 'IEF', 'GLD', 'SLV', 'USO', 'UNG',
78
+ 'VXX', 'FXE', 'FXY', 'FXB', 'FXA', 'FXC', 'FXF', 'XAU', 'XAG', 'XPT', 'XPD', 'XME', 'XHB', 'XLF', 'XLY', 'XLC', 'XLI', 'XLE',
79
+ 'XLV', 'XLP', 'XLRE', 'XLK', 'XLU', 'XLC', 'XLB', 'XITK', 'XNTK', 'XNWK', 'XNGK']
80
+ def fetch_crypto_data(start_date, end_date, *, locale = 'global', market_type = 'crypto'):
81
+ # Generate the date range
82
+ dates = pd.date_range(start=start_date, end=end_date, freq='D')
83
+
84
+ all_data = []
85
+ for date in dates:
86
+ formatted_date = date.strftime('%Y-%m-%d')
87
+ daily_data = pd.DataFrame(client.get_grouped_daily_aggs(formatted_date, locale=locale, market_type=market_type))
88
+ all_data.append(daily_data)
89
+
90
+ newdata = pd.concat(all_data)
91
+ if market_type == 'crypto':
92
+ newdata= newdata[newdata['ticker'].str.endswith('USD')]
93
+ elif market_type == 'stocks':
94
+ newdata= newdata[~newdata['ticker'].isin(etfs)]
95
+ else:
96
+ pass
97
+ newdata["totalvol"] = newdata.volume*newdata.close
98
+ newdata["totalvol2"] = newdata.volume/newdata.close
99
+ # Sort the data by timestamp to ensure correct EMA calculation
100
+ newdata.sort_values(by='timestamp', inplace=True)
101
+
102
+ # Calculate the EMA of the `totalvol` column
103
+ # `span` is set to 30 for a 30-day EMA
104
+ newdata['totalvol_ema'] = newdata.groupby('ticker')['totalvol'].transform(lambda x: x.ewm(span=30, adjust=False).mean())
105
+ newdata['totalvol2_ema'] = newdata.groupby('ticker')['totalvol2'].transform(lambda x: x.ewm(span=30, adjust=False).mean())
106
+ return newdata
107
+
108
+ # Example usage
109
+ #start_date = '2020-01-01'
110
+ #end_date = '2024-03-27'
111
+ #crypto_data = fetch_crypto_data(start_date, end_date)
112
+
113
+
114
+ def get_crypto_index(crypto_data, howmany = 20, func = lambda x: x):
115
+
116
+ ser = pd.Series(np.ones(howmany)).map(func)
117
+ p = pd.Series(np.ones(howmany))
118
+ valdict = {}
119
+ dfdict = {}
120
+ crypto_data.sort_values('timestamp', inplace = True, ascending = True)
121
+ for d, df in crypto_data.groupby('timestamp'):
122
+ df = df[df.open > 0.01]
123
+ df = df.sort_values('totalvol_ema', ascending=False).head(howmany)
124
+ #indopen =np.average(df.open/p, weights = ser)
125
+ indopen = np.average(df.open.values, weights=ser.values)
126
+ #indclose =np.average(df.close/p, weights = ser)
127
+ indclose = np.average(df.close.values, weights=ser.values)
128
+ ser = df.totalvol_ema.map(func)
129
+ p = df.close
130
+ valdict[d] = {'open': indopen, 'close': indclose}
131
+ dfdict[d] = pd.DataFrame({'ticker':df.ticker, 'weight':ser, 'close': df.close})
132
+
133
+ first_key = next(iter(valdict))
134
+ del valdict[first_key]
135
+ del dfdict[first_key]
136
+ vals = pd.DataFrame(valdict).T
137
+ vals.index = pd.to_datetime(vals.index, unit = 'ms')
138
+ vallist =[]
139
+ for key, val in dfdict.items():
140
+ val['date'] = pd.to_datetime(key, unit = 'ms')
141
+ vallist.append(val)
142
+ dfs = pd.concat(vallist)
143
+ return vals, dfs
144
+
145
+ def update_weights(fname="/tmp/wts.csv", **kwargs):
146
+ start_date, end_date = calc_dates()
147
+ crypto_data = fetch_crypto_data(start_date, end_date, **kwargs)
148
+ _, dfs = get_crypto_index(crypto_data)
149
+ retval = dfs[dfs.date == dfs.date.max()]
150
+ retval.to_csv(fname, index = False)
151
+ return retval
index_interface.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import plotly.express as px
3
+ from cryptoindex import *
4
+ import pandas as pd
5
+ from updater import *
6
+ from time import sleep
7
+ from functools import partial
8
+ import argparse
9
+
10
+
11
+ last_start_date = None
12
+ last_end_date = None
13
+ is_current = False
14
+ v = None
15
+ t = 0
16
+ real_time_data = None
17
+ is_historical = False
18
+
19
+ update_weights1()
20
+
21
+ """ def mytimer(interval=60):
22
+ while True:
23
+ print("Timer: ", t)
24
+ t += 1
25
+ sleep(interval)
26
+
27
+ threading.Thread(target=mytimer, daemon=True).start()
28
+ """
29
+
30
+ def plot_index_prices(start_date, end_date, **kwargs):
31
+ global last_start_date, last_end_date, is_current, v
32
+
33
+ if start_date != last_start_date or end_date != last_end_date:
34
+ last_start_date = start_date
35
+ last_end_date = end_date
36
+ is_current = False
37
+
38
+ if not is_current:
39
+ cryptodf = fetch_crypto_data(start_date = start_date, end_date = end_date, **kwargs)
40
+ v, _ = get_crypto_index(cryptodf, func = np.sqrt)
41
+ is_current = True
42
+ _, _, _, output = do_sharpe(v.close)
43
+ fig = px.line(v, x=v.index, y='close', title='Index Prices')
44
+ fig.update_xaxes(rangeslider_visible=True)
45
+ return fig, output
46
+
47
+ def realtime_update_weighted_prices(fname="/tmp/wts.csv"):
48
+ if should_update_weights():
49
+ # If it's time to update the weights, spawn a thread to do so
50
+ threading.Thread(target=update_weights1, daemon=True).start()
51
+ last_day = pd.read_csv(fname, parse_dates=["date"])
52
+ prices = update_day(last_day)
53
+ _, _, _, output = do_sharpe(prices, days = False)
54
+ fig = px.line(prices, x=prices.index, y=prices.values, title='Index Today')
55
+ return fig, output
56
+
57
+ def make_graph(choice, start_date = None, end_date = None, fname = "/tmp/wts.csv", **kwargs):
58
+ if choice == "Historical":
59
+ fig,stats = plot_index_prices(start_date, end_date, **kwargs)
60
+
61
+ else:
62
+ fig, stats =realtime_update_weighted_prices(fname)
63
+
64
+ return gr.Plot(fig), gr.Markdown(stats)
65
+
66
+ if __name__ == "__main__":
67
+ parser = argparse.ArgumentParser()
68
+ parser.add_argument("--data_file" , default="/tmp/wts.csv", help="Weights for realtime computation")
69
+ parser.add_argument("--locale", default = 'global', help="the locale")
70
+ parser.add_argument("--market_type", default = 'crypto', help="the market type")
71
+ parser.add_argument("--share", action = "store_true", help="share the interface")
72
+ args = parser.parse_args()
73
+ make_graph_flex = partial(make_graph, fname = args.data_file, locale = args.locale, market_type = args.market_type)
74
+ update_weights1(fname=args.data_file, locale = args.locale, market_type = args.market_type)
75
+ with gr.Blocks() as iface: # Use () for context manager
76
+
77
+
78
+ startdatebox = gr.Textbox(label="Start Date")
79
+ enddatebox = gr.Textbox(label="End Date")
80
+ radio = gr.Radio(choices=["Historical", "Real-time"], label="graph type")
81
+ update_button = gr.Button("Update Graph") # Add a button to trigger the graph update
82
+
83
+
84
+
85
+ theplot = gr.Plot()
86
+ thestats = gr.Markdown()
87
+ radio.change(fn = make_graph_flex, inputs = [radio, startdatebox, enddatebox], outputs = [theplot, thestats])
88
+ update_button.click(fn = make_graph_flex, inputs = [radio, startdatebox, enddatebox], outputs = [theplot, thestats])
89
+ iface.launch(share=args.share)
updater.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import threading
3
+ from cryptoindex import update_weights
4
+
5
+
6
+ # Global variable to track when the weights were last updated
7
+ last_update = None
8
+
9
+ def update_weights1(**kwargs):
10
+ update_weights(**kwargs)
11
+ # Your logic to update weights goes here
12
+ print("Weights updated.")
13
+ global last_update
14
+ last_update = datetime.datetime.now()
15
+
16
+ def should_update_weights():
17
+ global last_update
18
+ current_time = datetime.datetime.now()
19
+
20
+ # Check if the current time is within the first 10 seconds after midnight
21
+ # and the last update wasn't today
22
+ if current_time.time() < datetime.time(0, 2, 0) and (last_update is None or current_time.date() > last_update.date()):
23
+ return True
24
+ return False
25
+