[코인 자동투자 봇 제작기 14] 선물 기능 추가
클로드에게 평가받아본 결과 추세 분석 알고리즘은 매우 체계적이고 유의미하단다 ^ㅇ^
이제 선물 기능을 만들고, 매수/매도 신호 발생 및 처리 기능을 만들 것이다.
선물 기능을 어떻게 추가해야 할 지 고민을 꽤 많이 했다.
챗지피티와 토론한 결과, 선물, 현물 on/off 기능을 만들어두고, 레버리지 설정도 환경변수를 통해 할 수 있도록 해 둔 후, 데이터를 불러오고 분석은 동일하게 진행할 것이다.
그러면 일단 config, data_control, notifier, main 코드를 모두 수정해야 한다.
Config
config 파일에서 추가해야 하는 내용은 주로 환경변수에 관한 내용이니, 환경변수도 함께 추가해주어야 한다.
우선 기존에 존재하던 환경변수 중 STO_FUT_RATE 는 제거하도록 하자. 현물과 선물은 계좌가 분리되어 있으므로 굳이 비율을 설정해줄 필요가 없다.
- FUTURES_USE : 선물 거래 활성화 여부
- FUTURES_LEVERAGE : 레버리지 비율
- FUTURES_MARGIN_TYPE : 마진 타입(CROSS, ISOLATED)
- FUTURES_COIN_TICKERS : 선물 거래를 할 코인 목록
이정도가 필요하겠다.
마진 타입은 교차 마진과 격리 마진이 있는데, 포지션에 투입했을 때 청산당하는 하한선을 공유할 것인지 독립적으로 활용할 것인지에 대한 내용이다.
- 교차 마진은 포지션 유지에는 유리하지만, 계좌 전체 잔고를 위험에 노출시킬 수 있다
- 격리 마진은 포지션이 독립적으로 관리되어, 손실이 제한적이지만, 충분한 증거금을 유지하지 않으면 포지션이 쉽게 청산될 수 있다
이를 잘 활용하자. 나는 리스크 관리를 위해 격리 마진을 택할 것이다.
보통은 청산 전에 스탑로스를 걸어두기 때문에 크게 상관은 없지만, 혹시 모를 상황에 대비하여 격리 마진을 사용하도록 하겠다.
config 함수에는 아래와 같이 추가해주면 된다. 기존에 있던 레버리지 비율 환경변수도 제거하고 새로 만들어두자. 선물 관련 환경변수를 따로 관리하기 위함이다.
이런식으로 환경변수를 저장해 두었다.
이제 config 코드를 수정해보자. 방법은 그 전과 동일하다.
import os
from dotenv import load_dotenv
class Config():
def __init__(self):
print("환경변수 로드 중...")
load_dotenv()
self.binance_access_key = os.getenv("BINANCE_ACCESS_KEY")
self.binance_secret_key = os.getenv("BINANCE_SECRET_KEY")
self.slack_api_key = os.getenv("SLACK_API_KEY")
self.slack_asset_channel_id = os.getenv("SLACK_ASSET_CHANNEL_ID")
self.slack_trade_channel_id = os.getenv("SLACK_TRADE_CHANNEL_ID")
self.slack_error_channel_id = os.getenv("SLACK_ERROR_CHANNEL_ID")
self.seed_money = os.getenv("SEED_MONEY")
self.coin_tickers = os.getenv("COIN_TICKERS")
self.futures_use = os.getenv("FUTURES_USE").lower() == "true"
self.futures_leverage = int(os.getenv("FUTURES_LEVERAGE"))
self.futures_margin_type = os.getenv("FUTURES_MARGIN_TYPE")
self.futures_coin_tickers = os.getenv("FUTURES_COIN_TICKERS")
print("환경변수 로드 완료")
print("환경변수 검증중...")
self.verify()
print("환경변수 검증 완료!")
def verify(self):
if not self.binance_access_key:
raise ValueError("binance access key 환경변수가 제대로 설정되지 않았습니다.")
elif not self.binance_secret_key:
raise ValueError("binance secret key 환경변수가 제대로 설정되지 않았습니다.")
elif not self.slack_api_key:
raise ValueError("slack api key환경변수가 제대로 설정되지 않았습니다.")
elif not self.slack_asset_channel_id:
raise ValueError("slack asset channel id 환경변수가 제대로 설정되지 않았습니다.")
elif not self.slack_trade_channel_id:
raise ValueError("slack trade channel id 환경변수가 제대로 설정되지 않았습니다.")
elif not self.slack_error_channel_id:
raise ValueError("slack error channel id 환경변수가 제대로 설정되지 않았습니다.")
elif not self.seed_money:
raise ValueError("seed money 환경변수가 제대로 설정되지 않았습니다.")
elif not self.coin_tickers:
raise ValueError("coin tickers 환경변수가 제대로 설정되지 않았습니다.")
elif not self.futures_use:
raise ValueError("futures_use 환경변수가 제대로 설정되지 않았습니다.")
elif not self.futures_leverage:
raise ValueError("futures_leverage 환경변수가 제대로 설정되지 않았습니다.")
elif not self.futures_margin_type:
raise ValueError("futures_margin_type 환경변수가 제대로 설정되지 않았습니다.")
elif not self.futures_coin_tickers:
raise ValueError("futures_coin_tickers 환경변수가 제대로 설정되지 않았습니다.")
각 함수( __init__, verify)의 아랫쪽에 추가된 선물 관련 환경변수를 확인하면 된다.
그리고 main 함수 첫부분에 선물에 투자할 것인지를 체크하도록 하자.
def main():
print("투자 프로그램을 시작합니다.")
# Config에서 환경변수 및 고정변수 불러오기
config = Config()
ticker_list = config.coin_tickers.split(" ")
future_use = bool(config.futures_use)
if future_use:
future_ticker_list = config.futures_coin_tickers.split(" ")
client = Client(config.binance_access_key, config.binance_secret_key)
data_control = Data_Control()
notifier = Notifier()
여기서 future_use 부분과 future_ticker_list 부분이 추가되었다.
Data_control
이번엔 데이터 수집 함수를 수정해보자.
선물 시장의 데이터는 현물 시장과 다른 점이 두가지 존재한다.
1. Funding Rate (자금 조달 비율)
- Funding Rate는 롱(Long) 포지션과 숏(Short) 포지션 간 수요 차이를 조정하기 위해 선물 시장에서 사용되는 메커니즘이다.
- 정기적으로 (8시간마다) 롱 포지션이 숏 포지션에, 혹은 반대로 자금을 지불한다.
- Funding Rate는 선물 가격이 현물 가격과 지속적으로 괴리되는 것을 방지하는 역할을 한다.
쉽게 말해서, 수요가 낮은 포지션 소유자에게 반대 포지션의 돈을 뺏어서 준다는 의미로 볼 수 있겠다.
- Funding Rate > 0 (양수):
- 롱(Long) 포지션이 숏(Short) 포지션에 자금을 지불
- 시장에서 롱 포지션의 수요가 더 높다는 의미
- Funding Rate < 0 (음수):
- 숏(Short) 포지션이 롱(Long) 포지션에 자금을 지불
- 시장에서 숏 포지션의 수요가 더 높다는 의미
이는 포지션 유지 비용으로 직결되고, 포지션 유지 비용이 높으면 해당 포지션을 빨리 정리하고자 하는 압박이 가해진다.
따라서, Funding Rate가 높은 경우 숏 포지션을 고려하고, Funding Rate가 낮거나 음수일 경우 롱 포지션을 고려하는 방향으로 움직일 수 있다. 어찌 보면 가장 직관적인 보조지표 하나를 추가로 얻은 것과 같다.
2. Open Interest (미청산 계약)
- Open Interest는 특정 자산에 대해 아직 청산되지 않은 모든 선물 계약의 총합
- 이는 선물 시장에서 현재 활성화된 포지션의 수요와 공급 상태를 반영
- Open Interest가 높으면 시장 참여자가 많고, 유동성이 높다는 의미
- 트렌드 강도 판단:
- Open Interest가 증가하는 경우, 새로운 자금이 유입되고 있음을 의미하며 강한 추세가 이어질 가능성이 큼.
- 반면, Open Interest가 감소하면 포지션이 청산되고 있으며, 시장이 안정화되거나 조정을 준비하고 있을 수 있다.
- 트렌드 반전 감지:
- 가격이 상승하지만 Open Interest가 감소하면, 상승 추세가 약화될 가능성이 있다.
- 반대로, 가격이 하락하면서 Open Interest가 증가하는 경우, 강한 매도 압력이 지속될 수 있다.
따라서. 현재 시장 참여자가 얼마나 많은지를 나타낸다. 시장 참여자 수에 대한 내용은 변동성이나, 매수/매도 압력으로 직결되기 때문에 이 또한 매우 중요한 지표라고 할 수 있겠다.
다만 Open Interest 데이터는 역사적 데이터 형태로 제공하지 않고, 오직 실시간 데이터 형태로만 제공되기 때문에 두 데이터 중 Funding Rate만 활용해볼 것이다.
이제 코드를 수정해 보자.
데이터 불러오기 함수는 아래와 같이 수정되었다.
def data(self,client,symbol,timeframe, limit = 300, futures=False):
symbol = f"{symbol}USDT"
if futures:
candles = client.futures_klines(symbol=symbol, interval=timeframe, limit=limit)
else:
candles = client.get_klines(symbol=symbol, interval=timeframe, limit=limit)
# 새로운 데이터를 DataFrame으로 변환
data = pd.DataFrame(candles, columns=[
"Open Time", "Open", "High", "Low", "Close", "Volume",
"Close Time", "Quote Asset Volume", "Number of Trades",
"Taker Buy Base Asset Volume", "Taker Buy Quote Asset Volume", "Ignore"
])
selected_columns = ["Open Time", "Open", "High", "Low", "Close", "Volume", "Taker Buy Base Asset Volume"]
data = data[selected_columns]
# 자료형 변환
data["Open"] = data["Open"].astype(float)
data["High"] = data["High"].astype(float)
data["Low"] = data["Low"].astype(float)
data["Close"] = data["Close"].astype(float)
data["Volume"] = data["Volume"].astype(float)
data["Taker Buy Base Asset Volume"] = data["Taker Buy Base Asset Volume"].astype(float)
# 시간 변환
data["Open Time"] = pd.to_datetime(data["Open Time"], unit='ms')
data["Taker Sell Base Asset Volume"] = data["Volume"] - data["Taker Buy Base Asset Volume"]
data["Open Time"] = pd.to_datetime(data["Open Time"], unit='ms') # 시간 변환
data = data.sort_values(by="Open Time").reset_index(drop=True)
if futures:
# Funding Rate 수집
funding_rate = client.futures_funding_rate(symbol=symbol)
funding_df = pd.DataFrame(funding_rate)
funding_df = funding_df.tail(300) # 최근 300개의 Funding Rate만 유지
funding_df["fundingRate"] = funding_df["fundingRate"].astype(float)
funding_df["fundingTime"] = pd.to_datetime(funding_df["fundingTime"], unit='ms')
# 5. 데이터 병합 (가장 최근 값으로 병합)
data = pd.merge_asof(data.sort_values("Open Time"), funding_df.sort_values("fundingTime"),
left_on="Open Time", right_on="fundingTime", direction="backward")
# 필요 없는 열 정리
data.drop(columns=["fundingTime", "time"], inplace=True)
return data
데이터 업데이트 함수는 아래와 같이 수정되었다.
def update_data(self, client, symbol, timeframe, existing_data, futures=False, funding_limit=3):
try:
# 새 데이터 수집 (3개 캔들 데이터만 요청)
candles = None
if futures:
candles = client.futures_klines(symbol=symbol, interval=timeframe, limit=3)
else:
candles = client.get_klines(symbol=symbol, interval=timeframe, limit=3)
# 새로운 데이터를 DataFrame으로 변환
temp_data = pd.DataFrame(candles, columns=[
"Open Time", "Open", "High", "Low", "Close", "Volume",
"Close Time", "Quote Asset Volume", "Number of Trades",
"Taker Buy Base Asset Volume", "Taker Buy Quote Asset Volume", "Ignore"
])
# 필요한 컬럼만 선택 및 전처리
selected_columns = ["Open Time", "Open", "High", "Low", "Close", "Volume", "Taker Buy Base Asset Volume"]
temp_data = temp_data[selected_columns]
temp_data["Open"] = temp_data["Open"].astype(float)
temp_data["High"] = temp_data["High"].astype(float)
temp_data["Low"] = temp_data["Low"].astype(float)
temp_data["Close"] = temp_data["Close"].astype(float)
temp_data["Volume"] = temp_data["Volume"].astype(float)
temp_data["Taker Buy Base Asset Volume"] = temp_data["Taker Buy Base Asset Volume"].astype(float)
temp_data["Taker Sell Base Asset Volume"] = temp_data["Volume"] - temp_data["Taker Buy Base Asset Volume"]
temp_data["Open Time"] = pd.to_datetime(temp_data["Open Time"], unit='ms')
# 선물 데이터에 추가 정보를 병합
if futures:
# Funding Rate 수집
funding_rate = client.futures_funding_rate(symbol=symbol, limit=funding_limit)
funding_df = pd.DataFrame(funding_rate)
funding_df["fundingRate"] = funding_df["fundingRate"].astype(float)
funding_df["fundingTime"] = pd.to_datetime(funding_df["fundingTime"], unit='ms')
# 데이터 병합
temp_data = pd.merge_asof(temp_data.sort_values("Open Time"), funding_df.sort_values("fundingTime"),
left_on="Open Time", right_on="fundingTime", direction="backward")
# 필요 없는 열 제거
temp_data.drop(columns=["fundingTime", "time"], inplace=True)
## `Open Time` 기준 병합
combined_data = pd.concat([existing_data, temp_data]).drop_duplicates(subset="Open Time", keep="last")
combined_data = combined_data.sort_values(by="Open Time").reset_index(drop=True)
if len(combined_data) > 140:
combined_data = combined_data.iloc[-140:].reset_index(drop=True)
return combined_data
except Exception as e:
print(f"데이터 업데이트 중 오류 발생: {e}")
return existing_data
두 함수에서 수정된 부분을 중심으로 살펴보자.
우선 데이터를 받아오는 부분에서 차이가 생겼다.
if futures:
candles = client.futures_klines(symbol=symbol, interval=timeframe, limit=limit)
else:
candles = client.get_klines(symbol=symbol, interval=timeframe, limit=limit)
타임프레임별로 분리되어있던 함수를 단순화했으며, 현물 데이터는 get_klines 함수를, 선물 데이터는 futures_klines 함수를 활용하도록 설정해 두었다.
타임프레임 변수 형식은 "1m", "5m", "1h" 등의 형태로 바뀌어야 한다.
따라서 메인 함수에는 아래와 같이 변경해야 한다.
for timeframe in ["1m", "5m", "1h"]:
data = data_control.data(client, symbol, timeframe, limit=300)
그 뒤에 Funding Rate 데이터를 추가하는 부분은 아래와 같이 코드를 추가하면 된다.
if futures:
# Funding Rate 수집
funding_rate = client.futures_funding_rate(symbol=symbol)
funding_df = pd.DataFrame(funding_rate)
funding_df = funding_df.tail(300) # 최근 300개의 Funding Rate만 유지
funding_df["fundingRate"] = funding_df["fundingRate"].astype(float)
funding_df["fundingTime"] = pd.to_datetime(funding_df["fundingTime"], unit='ms')
# 5. 데이터 병합 (가장 최근 값으로 병합)
data = pd.merge_asof(data.sort_values("Open Time"), funding_df.sort_values("fundingTime"),
left_on="Open Time", right_on="fundingTime", direction="backward")
# 필요 없는 열 정리
data.drop(columns=["fundingTime", "time"], inplace=True)
이제 메인 로직을 수정해 보자.
Main
메인 로직에서 필요한 로직은 크게 특별한 것은 없고, 선물 사용이 On 되어있으면 선물 관련 데이터를 추가적으로 불러오고, 자산정보를 추가적으로 로딩하는 작업이 필요하다.
아래는 초기 데이터 수집 부분이다.
if future_use:
for symbol in future_ticker_list:
futures_data[symbol] = {}
for timeframe in ["1m", "5m", "1h"]:
future_data = data_control.data(client, symbol, timeframe, limit=300, futures=True)
# 각 데이터에 대한 기술적 지표 계산
future_data = data_control.cal_moving_average(future_data)
future_data = data_control.cal_rsi(future_data)
future_data = data_control.cal_bollinger_band(future_data)
future_data = data_control.cal_obv(future_data)
# 1시간봉, 5분봉에 대한 추세 분석 지표 추가
if timeframe == "1h" or timeframe == "5m":
future_data = data_control.LT_trand_check(future_data)
# 비어있는 값 제거
future_data = future_data.dropna()
# 데이터 길이는 140개로 제한. (120일 이평선 계산을 위함.)
if len(future_data) > 140:
future_data = future_data.iloc[-140:].reset_index(drop=True)
futures_data[symbol][timeframe] = future_data
# 남은 데이터에 대한 VP, TPO 계산
profile_df, sr_levels = data_control.cal_tpo_volume_profile(future_data)
vp_data[symbol][timeframe] = profile_df
tpo_data[symbol][timeframe] = sr_levels
이 아래는 데이터 업데이트 부분이다.
if future_use:
for ticker in future_ticker_list:
for timeframe in ["1m", "5m", "1h"]:
futures_data[ticker][timeframe] = data_control.update_data(
client, ticker, timeframe, futures_data[ticker][timeframe], futures=True
)
updated_data = futures_data[ticker][timeframe]
# 업데이트된 데이터에 대한 기술적 지표 추가
updated_data = data_control.cal_moving_average(updated_data)
updated_data = data_control.cal_rsi(updated_data)
updated_data = data_control.cal_bollinger_band(updated_data)
updated_data = data_control.cal_obv(updated_data)
# 만약 1시간봉/5분봉인 경우 트렌드 체크 추가
if timeframe == "1h" or timeframe == "5m":
updated_data = data_control.LT_trand_check(updated_data)
# TPO/VP 데이터 업데이트
futures_data[ticker][timeframe] = updated_data
data = futures_data[ticker][timeframe]
profile_df, sr_levels = data_control.cal_tpo_volume_profile(data)
vp_data[ticker][timeframe] = profile_df
tpo_data[ticker][timeframe] = sr_levels
기존에 만들어둔 데이터 불러오기 함수에서 변수명만을 바꾼 것이다.
Notifier
알림 함수에서는 선물 관련 자산 조회 함수와 투자 한도 함수를 새로 만들어 두어야 한다. 로직은 별 차이 없으니 코드만 보고 패스...
선물 자산 조회 함수
def get_futures_asset_info(self):
"""
선물 계좌 정보를 조회하고 self.asset_info에 저장.
"""
try:
# 1. 선물 계좌 잔액 조회
futures_balances = self.client.futures_account_balance()
for balance in futures_balances:
asset = balance['asset']
if asset not in self.future_target_coins:
continue # future_target_coins에 없는 자산은 건너뛰기
balance_amount = float(balance['balance'])
withdraw_available = float(balance['withdrawAvailable'])
# 2. 잔액 정보 저장
self.asset_info[asset] = {
"balance": balance_amount,
"withdraw_available": withdraw_available,
"positions": []
}
# 3. 선물 포지션 정보 조회
futures_positions = self.client.futures_position_information()
for position in futures_positions:
symbol = position['symbol']
if symbol.replace("USDT", "") not in self.future_target_coins:
continue # 선물 대상 코인에 없는 경우 스킵
position_amt = float(position['positionAmt'])
entry_price = float(position['entryPrice'])
unrealized_profit = float(position['unRealizedProfit'])
leverage = int(position['leverage'])
if position_amt != 0: # 포지션이 있을 경우만 저장
self.asset_info[symbol] = {
"position_amt": position_amt,
"entry_price": entry_price,
"unrealized_profit": unrealized_profit,
"leverage": leverage,
"margin_type": position['marginType']
}
except Exception as e:
print(f"선물 계좌 정보 조회 중 오류 발생: {e}")
선물 자산 투자 한도 계산 함수
def futures_get_limit_amount(self):
"""
선물 계좌의 투자 한도를 계산하는 함수.
"""
try:
# 1. USDT 잔액 조회 (선물 계좌)
usdt_balance = float(self.asset_info.get("USDT", {}).get("balance", 0))
available_balance = float(self.asset_info.get("USDT", {}).get("withdraw_available", 0))
# 2. 선물 계좌의 포지션 가치 계산
coin_values = {}
total_asset = usdt_balance
for symbol in self.future_target_coins:
if symbol == "USDT":
continue
# 선물 포지션 정보 가져오기
position_info = self.asset_info.get(f"{symbol}USDT", {})
position_amt = float(position_info.get("position_amt", 0))
entry_price = float(position_info.get("entry_price", 0))
# 포지션 크기 및 가치 계산
position_value = abs(position_amt) * entry_price
coin_values[symbol] = position_value
total_asset += position_value
# 3. 코인 개수 및 균등 배분 금액 계산
coin_count = len(self.future_target_coins) - 1 # USDT 제외
if coin_count == 0:
raise ValueError("선물 대상 코인이 없습니다.")
target_amount_per_coin = total_asset / coin_count
# 4. 매수/매도 가능 금액 계산
limit_amounts = {}
negative_sum = 0
negative_count = 0
for symbol in self.future_target_coins:
if symbol == "USDT":
continue
# 목표 금액에서 현재 포지션 가치 차감
limit_amount = target_amount_per_coin - coin_values.get(symbol, 0)
# 초과 보유 시 0으로 설정하고, 초과분을 누적
if limit_amount < 0:
negative_sum += abs(limit_amount)
negative_count += 1
limit_amounts[symbol] = 0
else:
limit_amounts[symbol] = limit_amount
# 5. 초과 포지션을 다른 코인들에게 분배
if negative_count > 0 and coin_count > negative_count:
additional_reduction = negative_sum / (coin_count - negative_count)
for symbol in self.future_target_coins:
if symbol == "USDT":
continue
if limit_amounts[symbol] > 0:
limit_amounts[symbol] -= additional_reduction
return limit_amounts
except Exception as e:
error_msg = f"선물 주문 가능 금액 계산 중 오류 발생: {str(e)}"
print(error_msg)
return {}
자산 정보 전송 함수
def send_asset_info(self, spot_limit_amount, futures_limit_amount, position_tracker=""):
"""
현물 및 선물 계좌 정보를 Slack에 전송하는 함수.
"""
try:
# 1. 현물 계좌 정보
usdt_balance = self.asset_info.get("USDT", {}).get("total_quantity", 0)
total_spot_asset = usdt_balance
spot_message = f"""
📊 현물 계좌 자산 현황
──────────────
💰 보유 USDT: {usdt_balance:,.2f} USDT
──────────────
"""
# 현물 자산 정보 추가
for symbol, info in self.asset_info.items():
if symbol == "USDT" or symbol not in self.target_coins:
continue
coin_value = info["total_quantity"] * info["current_price"]
total_spot_asset += coin_value
spot_message += f"""
🪙 {symbol} (현물):
수량: {info['total_quantity']:.8f}
거래 가능 수량: {info['free']:.8f}
거래 중 잠김: {info['locked']:.8f}
평균매수가: {info['average_buy_price']:,.2f} USDT
현재가격: {info['current_price']:,.2f} USDT
평가금액: {coin_value:,.2f} USDT
수익률: {info['profit_rate']:.2f}%
코인별 투자한도: {spot_limit_amount.get(symbol, 0):,.2f} USDT
──────────────"""
# 2. 선물 계좌 정보
usdt_futures_balance = self.asset_info.get("USDT", {}).get("balance", 0)
total_futures_asset = usdt_futures_balance
futures_message = f"""
📊 선물 계좌 자산 현황
──────────────
💰 선물 USDT 잔액: {usdt_futures_balance:,.2f} USDT
──────────────
"""
# 선물 자산 정보 추가
for symbol, info in self.asset_info.items():
if "USDT" not in symbol or symbol.replace("USDT", "") not in self.future_target_coins:
continue
position_value = abs(info.get("position_amt", 0)) * info.get("entry_price", 0)
total_futures_asset += position_value
futures_message += f"""
🪙 {symbol} (선물):
포지션 크기: {info.get('position_amt', 0):.8f}
진입가격: {info.get('entry_price', 0):,.2f} USDT
현재 미실현 손익: {info.get('unrealized_profit', 0):,.2f} USDT
레버리지: {info.get('leverage', 0)}x
포지션 가치: {position_value:,.2f} USDT
선물 투자한도: {futures_limit_amount.get(symbol.replace("USDT", ""), 0):,.2f} USDT
──────────────"""
# 3. 총 자산 및 수익률
total_asset = total_spot_asset + total_futures_asset
total_message = f"""
💵 총 자산 (현물 + 선물): {total_asset:,.2f} USDT
💵 전체 수익률: {((float(total_asset) - float(self.config.seed_money)) / float(self.config.seed_money) * 100):.2f}%
──────────────
"""
# 4. 최종 메시지 작성
full_message = spot_message + position_tracker + futures_message + total_message
# 5. 메시지 전송
self.send_slack_message(self.config.slack_asset_channel_id, full_message)
except Exception as e:
print(f"자산 보고 오류: {str(e)}")
자산 정보 전송 함수는 기존 함수를 수정한 것이다. 선물에 대한 내용만 간단히 몇가지 추가해 주었다.
이제 메인 함수 내에서 이렇게 호출해주면 된다.
notifier.get_asset_info()
notifier.get_futures_asset_info()
spot_limit_amount = notifier.get_limit_amount()
future_limit_amount = notifier.futures_get_limit_amount
notifier.send_asset_info(spot_limit_amount, future_limit_amount)
이러면 알아서 투자 한도를 조회하고, 자산정보를 전송한 후 투자를 시작하게 된다.