ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬으로 만들어 본 주식 계산기
    Python/파이썬과 주식 2025. 3. 28. 17:10
    반응형

    1. 매수 매도 가격 입력 -> 예상 수익률
    2. 매수 가격, 목표 수익률 입력 -> 매도 가격 

    매수 매도 수수료 및 증권 거래세를 포함.
    다만 실제 거래에서는 10원 단위 절사 등을 하는데, 완벽하게 같지는 않습니다.  
    참고만 하시구요. 

    혹시 오류가 있다면 리플 남겨주세요. 

    pip install ttkbootstrap

    import os
    import tkinter as tk
    from tkinter import font, ttk
    
    from ttkbootstrap import Style
    
    BUY_FEE = 0.015
    SELL_FEE = 0.015
    TAX = 0.15
    
    
    def on_radiobutton_click(*args):
        if selected_option_var.get() == 'profit_rate':
            buy_price_label.configure(font=BOLD_FONT)
            sell_price_label.configure(font=BOLD_FONT)
            quantity_label.configure(font=BOLD_FONT)
            profit_rate_label.configure(font=DEFAULT_FONT)
        elif selected_option_var.get() == 'sell_price':
            buy_price_label.configure(font=BOLD_FONT)
            sell_price_label.configure(font=DEFAULT_FONT)
            quantity_label.configure(font=BOLD_FONT)
            profit_rate_label.configure(font=BOLD_FONT)
    
    
    def on_key_release(entry):
        format_number(entry)
        if selected_option_var.get() == 'profit_rate':
            calculate_profit()
        elif selected_option_var.get() == 'sell_price':
            calculate_sell_price()
    
    
    def format_number(entry):
        value = entry.get().replace(',', '')
        if value.isdigit():
            formatted_value = f'{int(value):,}'
            entry.delete(0, tk.END)
            entry.insert(0, formatted_value)
    
    
    def calculate_sell_price(*args):
        try:
            buy_price = float(buy_price_entry.get().replace(',', ''))
            quantity = int(quantity_entry.get().replace(',', ''))
            profit_rate = float(profit_rate_entry.get()) / 100
            buy_fee_rate = float(buy_fee_entry.get()) / 100
            sell_fee_rate = float(sell_fee_entry.get()) / 100
            tax_rate = float(tax_entry.get()) / 100
    
            total_buy = buy_price * quantity * (1 + buy_fee_rate)
            total_buy_fee = buy_price * quantity * buy_fee_rate
            sell_price = buy_price * (1 + buy_fee_rate) * (1 + profit_rate) / (1 - sell_fee_rate - tax_rate)
            total_sell = sell_price * quantity * (1 - sell_fee_rate - tax_rate)
            total_sell_fee_tax = sell_price * quantity * (sell_fee_rate + tax_rate)
            profit = total_sell - total_buy
    
            sell_price_entry.delete(0, tk.END)
            sell_price_entry.insert(0, f'{sell_price:,.2f}')
            fee_entry.delete(0, tk.END)
            fee_entry.insert(0, f'{total_buy_fee + total_sell_fee_tax:,.2f}')
            profit_entry.delete(0, tk.END)
            profit_entry.insert(0, f'{profit:,.2f}')
        except Exception as e:
            print(e)
    
    
    def calculate_profit(*args):
        try:
            buy_price = float(buy_price_entry.get().replace(',', ''))
            sell_price = float(sell_price_entry.get().replace(',', ''))
            quantity = int(quantity_entry.get().replace(',', ''))
            buy_fee_rate = float(buy_fee_entry.get()) / 100
            sell_fee_rate = float(sell_fee_entry.get()) / 100
            tax_rate = float(tax_entry.get()) / 100
    
            total_buy = buy_price * quantity * (1 + buy_fee_rate)
            total_buy_fee = buy_price * quantity * buy_fee_rate
            total_sell = sell_price * quantity * (1 - sell_fee_rate - tax_rate)
            total_sell_fee_tax = sell_price * quantity * (sell_fee_rate + tax_rate)
            profit = total_sell - total_buy
            profit_rate = (profit / total_buy) * 100
    
            fee_entry.delete(0, tk.END)
            fee_entry.insert(0, f'{total_buy_fee + total_sell_fee_tax:,.2f}')
            profit_entry.delete(0, tk.END)
            profit_entry.insert(0, f'{profit:,.2f}')
            profit_rate_entry.delete(0, tk.END)
            profit_rate_entry.insert(0, f'{profit_rate:,.2f}')
        except Exception as e:
            print(e)
    
    
    def toggle_always_on_top():
        if always_on_top_var.get():
            root.wm_attributes('-topmost', 1)  # 항상 위
        else:
            root.wm_attributes('-topmost', 0)  # 기본 상태
    
    
    root = tk.Tk()
    root.title('주식 계산기')
    root.wm_attributes('-topmost', 1)
    
    if os.path.isfile('icon.ico'):
        root.iconbitmap('icon.ico')
    
    style = Style(theme='superhero')
    
    DEFAULT_FONT = font.nametofont("TkDefaultFont")
    BOLD_FONT = font.Font(**{**DEFAULT_FONT.actual(), 'weight': 'bold', 'underline': 1})
    
    frame1 = ttk.Frame(root, padding=(10, 10, 10, 0))
    frame1.pack()
    
    selected_option_var = tk.StringVar(value='profit_rate')
    selected_option_var.trace_add("write", on_radiobutton_click)
    profit_rate_radio = ttk.Radiobutton(frame1, text='수익률', variable=selected_option_var, value='profit_rate',
                                        style='Toolbutton')
    profit_rate_radio.grid(row=0, column=1)
    sell_price_radio = ttk.Radiobutton(frame1, text='매도가격', variable=selected_option_var, value='sell_price',
                                       style='Toolbutton')
    sell_price_radio.grid(row=0, column=2)
    
    frame2 = ttk.Frame(root, padding=10)
    frame2.pack()
    
    buy_price_label = ttk.Label(frame2, text='매수가격')
    buy_price_label.configure(font=BOLD_FONT)
    buy_price_label.grid(row=0, column=0, sticky='e')
    buy_price_entry = ttk.Entry(frame2)
    buy_price_entry.grid(row=0, column=1)
    buy_price_entry.bind('<KeyRelease>', lambda e: on_key_release(buy_price_entry))
    
    sell_price_label = ttk.Label(frame2, text='매도가격')
    sell_price_label.configure(font=BOLD_FONT)
    sell_price_label.grid(row=1, column=0, sticky='e')
    sell_price_entry = ttk.Entry(frame2)
    sell_price_entry.grid(row=1, column=1)
    sell_price_entry.bind('<KeyRelease>', lambda e: on_key_release(sell_price_entry))
    
    quantity_label = ttk.Label(frame2, text='수량')
    quantity_label.configure(font=BOLD_FONT)
    quantity_label.grid(row=2, column=0, sticky='e')
    quantity_entry = ttk.Entry(frame2)
    quantity_entry.grid(row=2, column=1)
    quantity_entry.bind('<KeyRelease>', lambda e: on_key_release(quantity_entry))
    
    profit_rate_label = ttk.Label(frame2, text='수익률(%)')
    profit_rate_label.configure(font=DEFAULT_FONT)
    profit_rate_label.grid(row=3, column=0, sticky='e')
    profit_rate_entry = ttk.Entry(frame2)
    profit_rate_entry.grid(row=3, column=1)
    profit_rate_entry.bind('<KeyRelease>', lambda e: on_key_release(profit_rate_entry))
    
    profit_label = ttk.Label(frame2, text='수익(원)')
    profit_label.grid(row=4, column=0, sticky='e')
    profit_entry = ttk.Entry(frame2)
    profit_entry.grid(row=4, column=1)
    
    fee_label = ttk.Label(frame2, text='수수료 및 세금(원)')
    fee_label.grid(row=5, column=0, sticky='e')
    fee_entry = ttk.Entry(frame2)
    fee_entry.grid(row=5, column=1)
    
    buy_fee_label = ttk.Label(frame2, text='매수 수수료(%)')
    buy_fee_label.grid(row=6, column=0, sticky='e')
    buy_fee_entry = ttk.Entry(frame2)
    buy_fee_entry.grid(row=6, column=1)
    buy_fee_entry.insert(0, str(BUY_FEE))
    buy_fee_entry.bind('<KeyRelease>', calculate_profit)
    
    sell_fee_label = ttk.Label(frame2, text='매도 수수료(%)')
    sell_fee_label.grid(row=7, column=0, sticky='e')
    sell_fee_entry = ttk.Entry(frame2)
    sell_fee_entry.grid(row=7, column=1)
    sell_fee_entry.insert(0, str(SELL_FEE))
    sell_fee_entry.bind('<KeyRelease>', calculate_profit)
    
    tax_label = ttk.Label(frame2, text='증권거래세(%)')
    tax_label.grid(row=8, column=0, sticky='e')
    tax_entry = ttk.Entry(frame2)
    tax_entry.grid(row=8, column=1)
    tax_entry.insert(0, str(TAX))
    tax_entry.bind('<KeyRelease>', calculate_profit)
    
    frame3 = ttk.Frame(root, padding=(10, 0, 10, 10))
    frame3.pack()
    always_on_top_var = tk.BooleanVar(value=True)
    always_on_top_checkbox = ttk.Checkbutton(frame3, text='항상 위', variable=always_on_top_var, command=toggle_always_on_top)
    always_on_top_checkbox.grid(row=9, column=0, sticky='w')
    
    root.mainloop()

     

    개선할 점.. 

    Configparser나 yaml 등을 이용해 
    BUY_FEE = 0.015
    SELL_FEE = 0.015
    TAX = 0.15
    이런 변수들을 외부에서 다룰 수 있도록 한다면 좋을 것이다.

    어렵지 않으니 직접 해보시는 것을 추천한다. 

    반응형
Designed by Tistory.