import websocket
import json
import threading
import time
from datetime import datetime, timedelta, timezone
import pandas as pd
import jwt
import uuid
import hashlib
import os

# 환경 변수 로드
from dotenv import load_dotenv
load_dotenv()

# 설정
TARGET_PCT = 0.2  # 0.2%
MARKET = "KRW-SEI"  # SEI 코인 마켓 코드
PROFIT_THRESHOLD = 0.2  # 0.2%
INVESTMENT_AMOUNT = 10000  # KRW 투자 금액

# 웹소켓 연결 변수
current_minute = None
open_price = None
upper_threshold = None
lower_threshold = None
count_upper = 0
count_lower = 0

# WebSocket 및 주문 실행 함수
def on_message(ws, message):
    global current_minute, open_price, upper_threshold, lower_threshold, count_upper, count_lower

    data = json.loads(message)
    
    if data['type'] == 'trade':
        trade_time_str = data['trade_time']  # 'HHMMSS' 형식
        trade_price = data['trade_price']
        trade_timestamp = data['timestamp']
        
        # KST 시간을 기준으로 분을 계산
        trade_datetime = datetime.fromtimestamp(trade_timestamp / 1000, timezone(timedelta(hours=9)))  # KST
        trade_minute = trade_datetime.replace(second=0, microsecond=0)
        
        if current_minute != trade_minute:
            # 새로운 분이 시작되었을 때
            if current_minute is not None:
                # 이전 분의 결과를 기록
                print(f"{current_minute}: Upper {count_upper} times, Lower {count_lower} times")
                
                # 매도 주문 설정 조건
                if count_upper >= 1:
                    # 매도 시그널이 발생했으므로, 해당 분의 매수 주문을 실행할 수 있음
                    pass  # 필요시 추가 로직
                
                # 여기에서 매수 주문 조건을 설정할 수 있음 (예: 특정 변동 빈도 이상 시)
            
            # 변수 초기화
            current_minute = trade_minute
            open_price = trade_price  # 시가 설정
            upper_threshold = open_price * (1 + TARGET_PCT / 100)
            lower_threshold = open_price * (1 - TARGET_PCT / 100)
            count_upper = 0
            count_lower = 0
        
        # 변동 조건 확인
        if trade_price >= upper_threshold:
            count_upper += 1
            # 매도 조건 충족: 구매한 가격 대비 0.2% 상승 시 매도
            execute_sell_order(trade_price)
        elif trade_price <= lower_threshold:
            count_lower += 1
            # 매수 조건 충족: 구매한 가격 대비 0.2% 하락 시 매수
            execute_buy_order(trade_price)

def on_error(ws, error):
    print(f"WebSocket error: {error}")

def on_close(ws, close_status_code, close_msg):
    print("WebSocket connection closed")

def on_open(ws):
    print("WebSocket connection opened")
    # SEI 코인의 실시간 거래 데이터 구독 요청
    subscribe_message = [
        {"ticket": "unique_ticket"},
        {
            "type": "trade",
            "codes": [MARKET],
            "channels": ["trade"]
        }
    ]
    ws.send(json.dumps(subscribe_message))

def run_websocket():
    ws_url = "wss://api.upbit.com/websocket/v1"
    ws = websocket.WebSocketApp(ws_url,
                                on_open=on_open,
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    ws.run_forever()

# 주문 실행 함수 구현
def place_order(side, price, volume):
    """
    실제 주문을 실행하는 함수입니다.
    """
    access_key = os.getenv('UPBIT_OPEN_API_ACCESS_KEY')
    secret_key = os.getenv('UPBIT_OPEN_API_SECRET_KEY')
    server_url = os.getenv('UPBIT_OPEN_API_SERVER_URL', 'https://api.upbit.com')
    
    query = {
        'market': MARKET,
        'side': side,
        'volume': str(volume),
        'price': str(price),
        'ord_type': 'limit',
    }

    if side == 'ask':
        # 연결된 매수 주문 ID를 설정할 수도 있습니다.
        pass  # 필요시에 구현

    query_string = urlencode(query, doseq=True)
    m = hashlib.sha512()
    m.update(unquote(query_string).encode("utf-8"))
    query_hash = m.hexdigest()

    payload = {
        'access_key': access_key,
        'nonce': str(uuid.uuid4()),
        'query_hash': query_hash,
        'query_hash_alg': 'SHA512',
    }

    jwt_token = jwt.encode(payload, secret_key, algorithm='HS512')
    if isinstance(jwt_token, bytes):
        jwt_token = jwt_token.decode('utf-8')

    authorization = f'Bearer {jwt_token}'
    headers = {"Authorization": authorization}

    try:
        response = requests.post(f"{server_url}/v1/orders", json=query, headers=headers)
        response.raise_for_status()
        order_uuid = response.json().get('uuid')
        print(f"Order placed: {side} {volume} at {price} KRW, UUID: {order_uuid}")
        return order_uuid
    except Exception as e:
        print(f"Error placing order: {e}")
        return None

def execute_buy_order(buy_price):
    """
    매수 주문을 실행합니다.
    """
    investment_kRW = INVESTMENT_AMOUNT
    volume = calculate_volume(buy_price, investment_kRW)
    order_uuid = place_order('bid', buy_price, volume)
    if order_uuid:
        print(f"Buy order placed: {volume} SEI at {buy_price} KRW")
        # 주문 체결 후 매도 주문을 설정하는 로직을 추가해야 합니다.
    else:
        print("Buy order failed")

def execute_sell_order(current_price):
    """
    매도 주문을 실행합니다.
    """
    # 이 예제에서는 단순화를 위해 매도 주문을 즉시 실행
    investment_kRW = INVESTMENT_AMOUNT
    volume = calculate_volume(current_price, investment_kRW)
    order_uuid = place_order('ask', current_price, volume)
    if order_uuid:
        print(f"Sell order placed: {volume} SEI at {current_price} KRW")
    else:
        print("Sell order failed")

def calculate_volume(current_price, investment_kRW=10000):
    """
    투자할 금액을 기준으로 매수할 물량을 계산합니다.
    """
    volume = investment_kRW / current_price
    return round(volume, 6)

if __name__ == "__main__":
    # 웹소켓 스레드 시작
    ws_thread = threading.Thread(target=run_websocket)
    ws_thread.daemon = True
    ws_thread.start()

    # 프로그램 종료까지 대기
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Program interrupted by user")
        exit()

WebSocket error: name 'urlencode' is not defined 에러 해결