제 관심 도메인인 '금융' 주제에서 해결하고자 하는 문제를 정의하고, 데이터셋을 이용해 머신러닝 모델을 만든 후 성능 및 인사이트 도출을 해보려합니다.
🌀Problem Situation
블록체인 기술은 대중화 측면에서 무궁무진한 가능성을 지니고 있습니다.
최근 NFT 시장에서는 급격한 하락세가 이어졌지만, 글로벌적으로 다시 회복 과정에 있습니다.
저는 이러한 단기적인 시장 변화에 주목하기보다는, 조금 더 중장기적인 흐름에서 NFT가 가지는 기술적인 혁신과 활용 가능성을 더욱 신뢰할 수 있다고 생각했습니다.
초기 NFT 시장에서는 적극적인 거래 활동이 과열되었지만, 이제는 현실적이고 실제적인 활용을 위한 생태계 구축 단계에 접어들고 있습니다.
저는 NFT 시장의 일시적인 변동성보다는 NFT가 가지는 중장기적인 기술적 혁신과 활용 가능성에 더 초점을 두었습니다.
이에 따라서, 제가 작년에 구매한 토지 NFT인 소량주의 Orbcity의 가격 예측을 위해 토지 NFT 대량주인 Decentraland와 Sandbox의 대량주 데이터를 활용하여 land NFT의 분석과 더불어 전반적인 시장 동향을 파악하고자합니다.
또한 변동성이 매우 큰 NFT 시장에서 단기적인 투자 전략 수립을 위해, 1일, 5일 뒤의 종가 예측도 함께 시도하려 합니다.
🌀3 Land NFTs information
가상 자산 거래 방식 : P2P거래
사용 가능한 콘텐츠 종류 : 게임, 미팅룸, 아트, 쇼핑몰
Decentraland | Sandbox | Orbcity | |
---|---|---|---|
흥행 시작 년도 | 2017 말 | 2020 중 | 2022 초 |
데이터 개수 | 1975 | 966 | 382 |
최근 마지막 거래량 | 129775680 | 133827632 | 430847 |
거래 토큰 | MAMA, LAND | SAND | ORB |
스마트 계약 플랫폼 | Ethereum | Ethereum | Binance |
VR 지원 | 지원 | 지원 | 미지원 |
최근 대략 시가총액 | $1,110,824,414 | $134,447,000 | $9,358,000 |
총 시가 순위 | 대략45위 | 대략 55위 | x |
트위터 팔로워 | 631,868 | 1,095,543 | 45,976 |
(이것은 4/7일에 알아본 것이므로, 시간에 따라 변동된다는 점 참고)
Orbcity NFT
블록체인 기술을 활용하여 발행된 게임 내 디지털 자산입니다.
P2E 게임(Pay-to-Earn : 게임 내에서의 활동을 통해 암호화폐나 가상 자산을 얻을 수 있는 게임) 의 형태로 참여자들이 게임을 즐기는 동시에 경제적인 이익을 얻을 수 있습니다.
이는 게임 내 경제 생태계를 구축하고, 블록체인 상에서 거래가 가능하며, 보유한 자산의 가치를 유지하고 확대할 수 있는 가능성을 제공합니다.
Orbcity NFT 거래 방법
가격은 ETH로 표시되며, 구매자는 ETH를 지갑에서 Orbcity NFT 판매자의 지갑 주소로 보내는 방식으로 디지털 자산 구매, 판매함.
🌀EDA
데이터 불러오기 : FinanceDataReader
사용
- Decentraland, Sandbox : 2021년부터 갑자기 흥행, 감소추세
- Orbcity : 2022년에 출시되자 마자 흥행, 감소추세
결측치는 다 제거해줌.
decentraland와 sandbox의 시작날짜를 맞추어줌.
- decentraland : (946,7)
- sandbox : (946,7)
- orbcity : (361, 7)
Feature Engineering
Target column
target_1d
: 1일 뒤 종가
target_5d
: 5일 뒤 종가
보조지표
SMA (Simple Moving Average) sm5
, sm20
- 이동평균선, 최근 _일 간의 종가 평균치
EMA (Exponential Moving Average) ema12
, ema26
- 지수이동평균선, 최근 _일 간의 가격 데이터를 가중치를 부여해 계산한 평균치
- 빠르게 변하는 시장에서 추세 파악에 용이함.
이동평균선 교차 cross
- 두 이동평균선의 차이(sm5, sm20) 계산 후, 그 차이의 부호 확인 → 부호가 다르다면, (즉 이동평균선 교차가 발생하면), 교차가 발생한 것으로 판단해 1로 표시함.
- sm5가 sm20보다 위로 올라가면, cross 값은 1로 설정.
- 교차 지점을 표시하는 binary 데이터 → 0 : 하락추세, 1 : 상승추세
MACD (Moving Average Convergence Divergence) macd
, signal
- 추세 전환을 예측하는데 사용되는 지표
- 빠른 선인 EMA12, 느린 선인 EMA26의 차이를 계산해 표시하며, 이를 시그널선이라는 또 다른 EMA선과 함께 사용해 주식 등의 추세 전환이나 매수/매도 시기를 파악에 사용
- signal은 macd를 더 부드러운 선으로 표현한 지표. 이를 통해, 추세 전환 시기를 더욱 민감하게 감지 가능 ( 추세 전환 신호)
RSI (Relative Strength Index) rsi
- 14일 간의 주가 상승분, 하락분 비교 → 과매수, 과매도 상태 파악 지표
- 일반적으로 30이하는 과매도 상태, 70이상은 과매수 상태
Bollinger Bands upper_band
, lower_band
- 이동평균선, 가격의 표준편차를 이용해 상한선(upper_band), 하한선(lower_band) 계산
- 이동평균선 주위에 일정한 거리만큼 위아래로 밴드를 그려서, 주식 등의 가격 움직임 분석 지표
- upper band : 상승 추세, lower band : 하락추세
def feature_engineering(df):
# 이동평균선 계산
df['sma5'] = df['Close'].rolling(window=5).mean()
df['sma20'] = df['Close'].rolling(window=20).mean()
df['ema12'] = df['Close'].ewm(span=12, adjust=False).mean()
df['ema26'] = df['Close'].ewm(span=26, adjust=False).mean()
# MACD 계산
df['macd'] = df['ema12'] - df['ema26']
df['signal'] = df['macd'].ewm(span=9, adjust=False).mean()
# RSI 계산
delta = df['Close'].diff()
gain, loss = delta.copy(), delta.copy()
gain[gain < 0] = 0
loss[loss > 0] = 0
df['gain'] = gain
df['loss'] = loss
avg_gain = gain.rolling(window=14).mean()
avg_loss = abs(loss.rolling(window=14).mean())
rs = avg_gain / avg_loss
df['rsi'] = 100 - (100 / (1 + rs))
# Bollinger Bands 계산
std = df['Close'].rolling(window=20).std()
df['upper_band'] = df['sma20'] + 2 * std
df['lower_band'] = df['sma20'] - 2 * std
# 이동평균선 교차 계산
diff = df['sma5'] - df['sma20']
sign = np.sign(diff)
df['cross'] = ((sign.shift(1) != sign) & (sign.shift(1).notnull())).astype(int)
# gain, loss drop
df.drop(['gain', 'loss'], axis=1, inplace=True)
# target column : 다음날의 종가 예측
df['target_1d'] = df['Close'].shift(-1)
# target column2 : 5일 후의 종가 예측
df['target_5d'] = df['Close'].shift(-5)
return df
Decentraland
sandbox의 시작년도와 맞추어, 과거의 것은 drop함. (2020-09-02~)
The Sandbox
→ 이처럼 대량주는 2021년 말에 가장 활발했던 것을 볼 수 있습니다.
2021년 말을 기준으로 큰폭으로 떨어지던 시기에는 무슨 일이 있던 것일까?
NFT 시장에서 가장 많이 쓰이는 가상자산인 이더(ETH)가 우크라이나 러시아 전쟁이 이어지면서 코인 가격 하락으로 인해, NFT 가치가 급격히 하락되었기 때문입니다.
NFT 법률지원 미비
러그풀로 인한 신뢰도 하락 (NFT 개발자가 투자자 모집 후, 투자금을 가로채고 프로젝트 중단하는 경우) → 거액의 투자 피해
Orbcity
orbcity는 1년치 데이터로 소량주 데이터가 너무 적어 예측이 힘들다.
(2022-04-10~2023-04)
가정 : Land NFT 간의 유사성이 높다.
대량주 데이터(Decentraland, Sandbox) 이용해 소량주 데이터(Orbcity) 예측
전이학습 : 대량주 데이터를 이용해 더 많은 정보를 얻고, 이를 바탕으로 소량주 데이터 예측 => 소량주 데이터의 한계 극복, 더욱 정확한 예측 모델 구축
대량주의 decentraland 데이터 (2020-09-02 ~ 2022-04-09) 를 orbcity와 합쳐 사용
- decentraland : (946,19)
- sandbox : (946,19)
- orbcity : (946,19)
🌀Modeling
data : Decentraland, Sandbox, Orbcity (946,19)
2년치 과거 데이터 → 7개월 테스트 데이터 예측
- train set : 2020-09-02 ~ 2022-09-27 (756개)
- test set : 2022-09-28~ 2023-04-05 (190개)
정규화 : MinMaxScaler
Base Model
기준 모델 : 평균 사용 (모델 예측의 하한선)
- R2 : 0.0
- RMSE of bse model 1.086
우리가 예측할 모델의 R2는 0보다 크며. RMSE는 1.086보다 작아야 한다!
🌀Decentraland
1. RandomForest
RMSE : 0.0623
R2 : 0.8104
Drop Feature
중요도가 적은 cross, rsi, volume, macd, signal, Date, lower_band를 지우고 돌려보자!
target='target_1d'
x = decen.drop(columns=[target, 'target_5d', 'cross','rsi', 'Volume', 'macd', 'signal', 'Date', 'lower_band'], axis=1)
y = decen[target]
x_train, x_test = x[0:int(len(x)*0.8)], x[int(len(x)*0.8):]
y_train, y_test = y[0:int(len(y)*0.8)], y[int(len(y)*0.8):]
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)
rf2 = RandomForestRegressor(criterion='squared_error',
min_samples_split=3,
random_state=42,
bootstrap=True,
oob_score=True,
max_features='sqrt')
param_grid = {
'n_estimators': [1000, 1100, 1200],
'max_depth': [8,9,10],
'min_samples_leaf':[2,3,4]
}
grid_search = GridSearchCV(estimator=rf2, param_grid=param_grid, cv=5, scoring='neg_mean_absolute_error')
grid_search.fit(x_train, y_train)
best_model = grid_search.best_estimator_
y_pred_rf2 = best_model.predict(x_test)
grid_search.best_estimator_
>> RandomForestRegressor(criterion='squared_error',
max_depth=8,
max_features='sqrt',
min_samples_leaf=3,
min_samples_split=3,
n_estimators=1000,
oob_score=True,
booststrap=True
random_state=42)
RMSE : 0.0513
R2 : 0.8713
→ drop feature 후 성능 개선!
5일 뒤는 아예 예측을 하지 못하였습니다.
RMSE : 0.1648
R2 : -0.3492
2. LSTM
target = 'target_1d'
x = decen.drop(columns=[target, 'target_5d'], axis=1)
y = decen[target]
# Convert to Unix timestamp
x['Date'] = x['Date'].astype(np.int64) // 10**9
# Apply MinMaxScaler to all columns except 'Date'
scaler = MinMaxScaler()
x_scaled = scaler.fit_transform(x.drop(columns=['Date']))
x_train, x_test = x_scaled[0:int(len(x_scaled)*0.8)], x_scaled[int(len(x_scaled)*0.8):]
y_train, y_test = y[0:int(len(y)*0.8)], y[int(len(y)*0.8):]
# Reshape input data to be 3-dimensional
x_train = x_train.reshape((x_train.shape[0], 1, x_train.shape[1]))
x_test = x_test.reshape((x_test.shape[0], 1, x_test.shape[1]))
# Initialize model
lstm = Sequential()
lstm.add(LSTM(50, activation='tanh', input_shape=(1, x_train.shape[2])))
lstm.add(Dense(16, activation="relu"))
lstm.add(Dense(1))
# Compile model
lstm.compile(loss='mse', optimizer='adam')
# Fit model to training data
lstm.fit(x_train, y_train, epochs=50, batch_size=64, verbose=0)
# Make predictions on test set
y_pred_lstm = lstm.predict(x_test)
1일 뒤
RMSE : 0.0433
R2 : 0.9082
→ randomforest보다 더 좋은 성능.
5일 뒤
RMSE : 0.0846
R2 : 0.6449
→ 역시, 1일 뒤보다는 예측 성능 떨어졌지만, randomforest는 5일은 아예 예측못하는 것에 비하면 나은 성능을 보였습니다.
3. [Weighted Average] RandomForest + LSTM
가중치를 달리 주었더니 더 좋은 성능!!
weights = np.arange(0.01, 1, 0.01)
best_weight = 0
best_rmse = float('inf')
best_r2 = -float('inf')
# Loop through weights and calculate performance metrics
for weight in weights:
y_pred_total = weight * y_pred_lstm.reshape(-1) + (1 - weight) * y_pred_rf2
rmse = mean_squared_error(y_test, y_pred_total, squared=False)
r2 = r2_score(y_test, y_pred_total)
if rmse < best_rmse:
best_weight = weight
best_rmse = rmse
best_r2 = r2
y_pred_total = best_weight*y_pred_lstm.reshape(-1) + (1-best_weight)*y_pred_rf2
- LSTM
- RMSE : 0.0433
- R2 : 0.9082
- RandomForest
- RMSE : 0.0513
- R2 : 0.8713
- RF+LSTM
- RMSE : 0.0359
- R2 : 0.9369
🌀Sandbox
- [Weighted Average] RandomForest + LSTM
- LSTM
- RMSE : 0.0503
- R2 : 0.8427
- RandomForest
- RMSE : 0.0396
- R2 : 0.9025
- LSTM+RF (58%, 42%)
- RMSE : 0.0396
- R2 : 0.9074
- LSTM
🌀Orbcity
- [Weighted Average] Randomforest + LSTM
- LSTM
- RMSE : 0.0216
- R2 : 0.8033
- RandomForest
- RMSE : 0.0160
- R2 : 0.8923
- LSTM + RM (28%, 72%)
- RMSE : 0.0147
- R2 : 0.9083
- LSTM
🌀Conclusion
Modeling Summary
Decentraland | Sandbox | Orbcity | |
---|---|---|---|
대량주 | 대량주 | 소량주 | |
RandomForest | 0.8713 | 0.9025 | 0.8923 |
LSTM | 0.9082 | 0.8427 | 0.8033 |
RF + LSTM | 0.9369 | 0.9074 | 0.9083 |
- RandomForest : 다수의 결정트리 이용해 예측을 수행해, 분산된 데이터에서도 좋은 성능을 보이며, 다양한 데이터 유형에서 잘 작동
- LSTM : 시계열 데이터에서 잘작동하며, 과거 시계열 데이터를 이용해 예측을 수행하므로 데이터의 흐름을 파악하는 능력이 뛰어남.
각각의 모델의 장점을 활용해 가중 평균을 취하면, 모델의 성능이 더 좋아질 수 있다.
각 모델의 성능을 고려하여 가중치를 조절할 수 있어, 더욱 정확한 예측이 가능한다.
가정 검증 완료
- 대량주 데이터를 소량주 데이터의 과거에 적용하는 것이 더 나은 성능을 보인다는 가정이 검증되었습니다.
- 이는 land nft 간의 유사성이 있다는 것을 의미하며, 이를 활용하여 소량주 데이터를 예측하는 데 효과적인 방법을 제시했습니다.
효과
- 대량주와 소량주 간의 관련성을 파악하여 비즈니스 전략을 개선하거나 새로운 제품 라인을 개발하는 등의 의사 결정
- 재고를 최적화하고 재고 비용을 절감하며, 공급망을 최적화하여 제품 공급에 대한 효율성을 높일 수 있습니다.
- 향후 NFT 시장의 변동성에 대한 인사이트를 제공합니다.
- 가격은 이동평균선, 지수이동평균선, 볼린져밴드 등의 지표에 민감하게 반응할 수 있으며, 이러한 지표를 활용하여 투자 전략을 구성하는 것이 중요합니다.
한계점
- 해당 모델로는, 장기적인 미래 예측 힘들다.1일 예측은 90% 정도는 맞췄지만, 5일 예측 성능은 낮았습니다. 데이터의 부족과 모델의 결과가 예측과 가설일 뿐이며, 실제 투자에 대한 결정은 매우 복잡하고 개인적인 판단이 필요합니다.
- 해당 결과는 투자 전략의 참고 자료로 활용하는게 좋을 것 같습니다. 투자자들은 NFT 커뮤니티, 이슈, 프로젝트, 게임 등 다른 요인에 대한 고려도 필수적입니다.
추가사항
이후에, 장기적인 미래 예측과 원금 손실에 대한 예측 등 추가적인 분석을 토대로 더욱 정확하고 유용한 예측 모델을 개발하고 싶습니다.
미래에 대한 정확한 예측이 불가능하므로 이 예측결과에 대한 투자결정은 신중하게 해야합니다. 또한, 투자결정은 다양한 요소를 고려하여 수행되어야 하며, 이 모델에서 사용된 데이터만으로는 충분한 정보를 제공하지 못할 수도 있습니다. 따라서, 모델 결과를 참고하여 투자를 결정하는 것은 항상 주의가 필요합니다.
'Mini Project' 카테고리의 다른 글
[학부 논문] Solving ReCAPTCHA v2 Challenge using Classification-based Approach with Vision Transformer (0) | 2023.10.10 |
---|---|
[Data Analysis] What game should I design for the next quarter? (0) | 2023.03.13 |