G-Research Crypto Forecasting(欠損値確認、コインごとの取引量)

やるといってもなにをしようかと。。。。EDAとかでデータ見せてくれてるものはあるけど、はあそうですか。。。って感じになってしまいがち。

予測するものは将来15分間の超過リターン(Target: Residual log-returns for the asset over a 15 minute horizon.)。具体的には下の画像。 f:id:iiiiikamirin:20211224153928p:plain

これ見る感じ、とりあえず各通貨ごとに重みづけした指数を作成しないと始まらないのでは??特徴量つくるにしても、終値の推移より指数対比の推移をみないと発見はないだろうなと思ったので、まずは指数を作ることに。さーっと共有されているNotebookみてみたけど、この指数作成しているっぽいものを見つけられなかったので自分で作ろうかと。

単純に「通貨のリターン」ー「重みづけ指数」みたいな特徴量作ったらそれなりにいい特徴量になるのでは??

  • 悩みポイント

  • timestampに抜けとかないのか??

df全体に関して欠損値を確認。vwap以外はなし。ただ、timestampがすべてそろっているかは別問題。

df = crypto_df.copy(deep= True)
df.columns = [str.lower(i) for i in df.columns]
df.isnull().sum(axis= 0)
timestamp         0
asset_id          0
count             0
open              0
high              0
low               0
close             0
volume            0
vwap              9
target       750338
dtype: int64

ではtimestampの抜けは?Dogeのように最近できて昔のデータがそもそもないやつは除いて確認してみたりした(na_mid列)けど、それでも結構抜け漏れあり。抜けもれあると1日変化と3日変化の区別がつかないと思うので、これはさすがに補完した方がよさそう。前の値とかで補完したら同じ話になるので、線形補完で。

pivot = df.pivot(index= "timestamp", columns= "asset_id", values= "close")
asset_id2name = asset_details.set_index("asset_id")["asset_name"].to_dict()

fillna = pivot.rename(columns= asset_id2name).fillna(method= "ffill").isnull().sum(axis= 0)
not_fillna = pivot.rename(columns= asset_id2name).isnull().sum(axis= 0)
fillna = pd.DataFrame(fillna).rename(columns= {0: "fillna"})
not_fillna = pd.DataFrame(not_fillna).rename(columns= {0: "not_fillna"})

na_check = pd.merge(fillna, not_fillna, left_index= True, right_index= True)
na_check["na_mid"] = na_check["not_fillna"] - na_check["fillna"]

f:id:iiiiikamirin:20211224161751p:plain

  • timestampの抜けを埋める。フルのtimestampを作成→それでreset_indexの方法で。

フルのtimestamp作成。すべて60(秒)間隔ではなかったけど、資産間でラグがあっていればいいかなと思ったのでよいことに。

full_timestamp = df.timestamp.unique()
pd.Series(np.diff(np.sort(full_timestamp))).value_counts()

f:id:iiiiikamirin:20211224162509p:plain

reset_indexかつ欠損値補完

・・・ここまでやって気づいたけど、欠損値ってもしやその1分でトレードがなかったときでは?????たしかに、夜中とかなくてもおかしくないか????

ということで、count(取引数)と一応Volume(取引量)の最小数を確認。せっかくなので最大と平均も。すると取引量最大のBitCoinでも最小は1ということは、欠損値は取引0=補完せずに欠損値であることに意味があるのでは。。線形補完は違うと思った。取引0=前の時点と変化なしなので終値などはfillnaでcountなどは0を入れればよい気が。

agg_dict = {
    "count": ["mean", "min", "max"],
    "volume": ["mean", "min", "max"],    
}

group = df.groupby("asset_id", as_index= False).agg(agg_dict)
group["asset_id"] = group["asset_id"].apply(lambda x: asset_id2name[x])
group.columns = ['_'.join(col) for col in group.columns]

f:id:iiiiikamirin:20211224164142p:plain

というか、このデータはへえ、って感じだったのでちょっとグラフ書いてみることに。取引数は中央値>平均値なのでやっぱり取引数の波は激しくあるタイミングでみんな集中して取引するみたいですな。大きく動いた後あとなのか同時なのか、下落なのか上昇なのか(下落っぽいけど)など深堀りの余地はありそう。特にDogeは中央値と平均値の差が激しい気がする。激しい=投機的コインのようなイメージ受けるけどな。実際に平均/中央値だしてみたらDogeが圧倒的。さすが柴犬。

import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns

# col = "count_mean"
col = [
    "count_mean",
    "count_median"    
]
show = group.set_index("asset_id_")\
    .loc[:, col]\
    .stack()\
    .reset_index()\
    .rename(columns= {"level_1": "hue", 0: "value"})

fig = plt.figure()
ax = fig.add_subplot()
# sns.barplot(data= group, x= "asset_id_", y= col, ax= ax)
sns.barplot(data= show, x= "asset_id_", y= "value", hue= "hue", ax= ax)
ax.tick_params(axis= "x",rotation = 270)
# ax.set_title(col)
ax.set_title(col[0].split("_")[0])

f:id:iiiiikamirin:20211224170229p:plain

平均/中央値

f:id:iiiiikamirin:20211224170722p:plain

平均/中央値(柴犬除き)

f:id:iiiiikamirin:20211224170841p:plain

あと1取引あたりのボリューム。大型のフローが入りやすいのか小型なのか。BitCoinは個人のすそ野広そうだし小型では??案の定Dogeあたりのマイナーコインのフローがでかい。まじでコインによって差がでた。

group["one_impact_mean"] = group.volume_mean / group.count_mean
group["one_impact_median"] = group.volume_median / group.count_median

col = [
    "one_impact_mean",
    "one_impact_median",
]
show = group.set_index("asset_id_")\
    .loc[:, col]\
    .stack()\
    .reset_index()\
    .rename(columns= {"level_1": "hue", 0: "value"})

fig = plt.figure()
ax = fig.add_subplot()
sns.barplot(data= show, x= "asset_id_", y= "value", hue= "hue", ax= ax)
ax.tick_params(axis= "x",rotation = 270)

f:id:iiiiikamirin:20211224171557p:plain