본문 바로가기

영웅문Global 핸들링

매수 / 매도 수행하기 - 2 (미니주문 창 핸들링하기)

728x90

지난 내용에 이어서 미니주문 창을 핸들링해보겠습니다. 지난 내용을 통해 미니주문 창을 호출할 수 있는 상태여야 하므로 관련 내용의 확인이 필요하다면 아래 링크를 이용해 주세요.

2023.11.28 - [영웅문 Global 핸들링] - 매수 / 매도 수행하기 - 1 (미니주문 창 호출하기)

 

매수 / 매도 수행하기 - 1 (미니주문 창 호출하기)

매수 / 매도를 수행하는 방법도 여러가지가 있을 것 같습니다. 그 중에서 저는 미니 주문창을 통해 수행해보려 합니다. 전체적인 수행 결과를 먼저 보시죠. 미니주문 창 우리가 사용할 미니주문

kyeyangdak.tistory.com

 

미니주문 창 - 매수 / 매도 구분

띄운 미니주문 창은 앞에서 알아본 것처럼 매수일 때와 매도일 때 약간의 차이가 있습니다. 그렇기 때문에 현재상태가 매수인지 매도인지 구분이 필요합니다.

def check_meme_gubun():
    button_controls = find_controls_recursively(mini_order_window, "Button")
    meme_gubun = ""
    idx = 3
    meme_button = None
    for button in button_controls:
        if button.window_text().startswith("매수"):
            meme_button = button
            meme_gubun = "매수"
            idx = 3
            break
        elif button.window_text().startswith("매도"):
            meme_button = button
            meme_gubun = "매도"
            idx = 4
            break
        else:
            meme_gubun = ""
    return meme_gubun, idx, meme_button

구분하는 방법은 화면에 버튼의 텍스트가 매수로 시작하는지 매도로 시작하는지 검사하는 것입니다. 매수로 시작하는 버튼이 있다면 매수 상태인 것이고, 매도로 시작하는 버튼이 있다면 매도 상태인 것입니다. 해당 기능은 체크를 위해 자주 사용해야 해서 함수로 만들었습니다.

 

미니주문 창 - 매수 / 매도 선택

앞서서 현재 미니주문 창이 매수 상태인지, 매도 상태인지 확인했습니다. 그러면 사용자가 매수 / 매도를 원하는 것에 따라 상태를 변경해 줘야 합니다. 그래서 사용자가 원하는 상태를 입력받고 이에 맞게 조작해 보겠습니다.

while True:
    if meme_gubun != user_meme_gubun:
        if user_meme_gubun == "매수":
            image_filename = 'images/mesu.png'
        else:
            image_filename = 'images/medo.png'
        
				# 모니터가 여러개일 경우 이미지를 못 찾을 수 있음.
        try:
            menu_location = pyautogui.locateCenterOnScreen(image_filename, confidence=0.9)
            if menu_location:
                pyautogui.click(menu_location)
                time.sleep(1)
        except:
            break
    # 체크
    temp_meme_gubun, _, _ = check_meme_gubun()
    if temp_meme_gubun == user_meme_gubun:
        break

현재 미니주문 창의 상태가 유저가 원하는 상태와 다를 때 유저가 원하는 상태로 변경하는 로직을 수행합니다. 매수 / 매도 선택을 위한 적절한 핸들링 방법을 찾지 못했습니다. 그래서 여기에서는 이미지를 비교해서 매수 / 매도 영역을 클릭하도록 했습니다.

 

미니주문 창 - 자동(현재가) 클릭

앞서서 이 항목이 체크되어야 가격 정보를 신뢰하고 로직을 수행할 수 있다고 했습니다. 이 영역을 클릭하는 기능은 핸들링이 가능하지만 현재 체크가 되어있는지, 체크가 되어있지 않은지 알 수가 없었습니다. 그래서 앞서서 매수 / 매도를 선택하기 위해 이미지 서치를 한 것처럼 체크 이미지 상태인지 체크해서 아닌 경우에 체크하도록 했습니다.

while True:
    if user_meme_gubun == "매수":
        image_filename = 'images/auto_mesu.png'
    else:
        image_filename = 'images/auto_medo.png'
    try:
        check_location = pyautogui.locateCenterOnScreen(image_filename)
        button_controls = find_controls_recursively(mini_order_window, "Button")
        if check_location:
            for button in button_controls:
                if "현재가" in button.window_text():
                    button.click()
										time.sleep(0.5)
                    break
    except:
        break

자동(현재가)을 선택했는데 뒤에서 알아볼 종류를 시장가로 선택하면 해당 값은 체크가 해제됩니다. 그럼에도 종류를 선택하는 방법을 적은 이유는 대부분 현재 가격을 알아야 로직을 통해 매수/매도를 판단할 수 있기 때문입니다. 그리고 다른 종류인 지정가 또는 AFTER지정 등의 옵션을 활용해 볼 수 있습니다.

 

미니주문 창 - 티커 입력

이제 띄운 미니주문 창을 통해 티커를 입력해 보겠습니다. 티커 입력 필드는 Edit 클래스를 사용하는데 매수 일 때와 매도 일 때 순서가 약간 달라집니다. 원인은 매도 창에는 Stop 필드가 더 있어서입니다. 어쨌든 티커를 입력하기 위한 소스는 아래와 같습니다.

for i in range(0, 10):
    edit_controls = find_controls_recursively(mini_order_window, "Edit")
    edit_controls[idx].type_keys(user_ticker, pause=0.3).type_keys('{ENTER}')
    time.sleep(1)

    print(f"매매 : {meme_gubun}")
    print(f"티커 : {edit_controls[idx].get_value()}")
    print(f"가격 : {edit_controls[idx+2].get_value()}")
    print(f"수량 : {edit_controls[idx+3].get_value()}")
    if edit_controls[idx].get_value() == user_ticker:
        break

Edit 컴포넌트를 가져온 다음 매수 / 매도 상태에 따라 구분했던 idx 값으로 티커를 판단합니다. (매수는 3, 매도는 4) 가져온 티커 컴포넌트에 ‘SOXL’을 타입 핑하는데 0.3초 간격으로 사람이 입력하는 것처럼 타이핑합니다. 전체를 붙여 넣는 로직으로 수행했더니 인식이 잘 안 됐습니다. 모두 입력 후 ENTER 명령으로 티커를 선택해 줍니다.

티커, 가격, 수량을 가져와서 출력해 줍니다. 티커를 다시 가져온 이유는 혹시라도 내가 원하는 티커로 설정이 안 됐을 경우 가격 정보가 다름으로써 발생하는 문제가 있을 수 있기 때문에 다시 한번 체크하기 위함입니다.

 

미니주문 창 - 종류 설정하기

어떤 종류로 매매를 수행할지 결정해야 합니다. 저는 본장 거래를 하고 있고 가격 확인 후 매매 의사결정을 하게 되면 즉시 거래가 이뤄지기를 바라기 때문에 시장가로 설정하고 있습니다. 종류 항목도 핸들링이 어렵습니다.

# 매매 종류 설정 방법 - 지정가로 우선 설정
edit_controls = find_controls_recursively(mini_order_window, "Edit")
for i in range(0, 10):
    if edit_controls[idx + 1].get_value() == "지정가":
        break
    else:
        edit_controls[idx + 1].parent().set_focus()
        edit_controls[idx + 1].parent().type_keys('{UP}')
        close_risk_notice_popup(main_window)
        time.sleep(0.5)
for i in range(0, 10):
    if edit_controls[idx + 1].get_value() == "시장가":
        break
    else:
        edit_controls[idx + 1].parent().set_focus()
        edit_controls[idx + 1].parent().type_keys('{DOWN}')
        time.sleep(0.5)

 

미니주문 창 - 수량 설정하기

주문을 위해서는 종목을 조회하고 가격과 수량을 입력해야 합니다. 가격은 현재가를 사용하는 것으로 커버할 수 있으나 수량은 입력해줘야 합니다. 아래 로직을 통해 앞서 설정한 값으로 수량을 설정합니다.

for i in range(0, 10):
    edit_controls[idx + 3].set_focus()
    edit_controls[idx + 3].type_keys(str(user_qty))
    time.sleep(1)
    print(f"설정수량 : {edit_controls[idx + 3].get_value()}")

    if edit_controls[idx + 3].get_value() == str(user_qty):
        break

 

미니주문 창 - 매매하기

이제 거의 다 왔습니다. 세팅한 값으로 매매를 진행합니다. (매매 버튼 클릭)

meme_button.click()
time.sleep(2)

2초를 기다리는 이유는 최종 확인을 위한 매매 확인창이 뜨기 때문입니다.

mini_order_confirm_window = None
for child in main_window.children():
    if child.window_text().startswith("해외주식"):
        mini_order_confirm_window = child
        break

해당 창을 스크린숏 합니다. 이를 통해 제대로 설정 후 주문이 들어갔는지 나중에 체크해 볼 수 있습니다.

# 거래 스크린샷
screenshot = mini_order_confirm_window.capture_as_image()
screenshot_file = f"order/mini_order_confirm_window_screenshot_{int(time.time())}.png"
screenshot.save(screenshot_file)

여기까지 작업이 되었다면 최종 확인 버튼을 클릭하면서 매매를 마무리합니다.

# 확인 버튼 클릭
for btn in find_controls_recursively(mini_order_confirm_window, "Button"):
    if "확인" in btn.window_text():
        btn.click()

여기까지 내용을 직접 실행해 보셨나요? 부족한 점이 있거나 어려운 점이 있다면 언제든지 댓글, 이메일로 문의하세요. 문의를 주시는데 시간을 쏟으신 만큼 최선을 다해 답변드리겠습니다.

다음은 매수 / 매도가 반영된 실시간 계좌 확인 방법에 대해 설명드리겠습니다.

관심의 표현은 저에게 큰 힘이 됩니다. 😍 도움을 주셔서 정말 감사합니다.

반응형