SBI証券の取引履歴から決済損益トップ5、ワースト5を抽出してみた


やってみたこと

SBI証券を使って、株のデイトレードをしている。
SBI証券HPへのログインを自動化してみた で、少しLGTMをいただけてうれしかったので、
もう少し実用的なこととして、ある期間のトレードでいくら儲かってるか、いくら損しているかがわかるようにしてみた。
具体的には、SBI証券HPから取引履歴のCSVファイルをダウンロードして、
各売買の決済損益を算出し、指定した日付からの決済損益と、その中からトップ5、ワースト5を出力してみた。

環境

  • Chrome 89.0.4389.128
  • ChromeDriver
  • Python 3.8

コード

以下コードでは、2021年1月1日以降の履歴を取得している。
合計の決済損益と、決済損益のトップ5とワースト5が出力される。

from selenium import webdriver
from selenium.webdriver import ChromeOptions 
from selenium.webdriver.chrome.webdriver import WebDriver
import csv
import io
import os
import sys
import time

WAIT_TIME = 5

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
item_code = None


def login(driver):
    driver.get('https://www.sbisec.co.jp/ETGate')

    loginid = driver.find_element_by_name('user_id').send_keys('userid')
    passwd = driver.find_element_by_name('user_password').send_keys('password')

    Log_in = driver.find_element_by_name('ACT_login').click()


def download_csvfile(driver, year, month, day):
    driver.get('https://site2.sbisec.co.jp/ETGate/?_ControlID=WPLETacR007Control')
    From_year = driver.find_element_by_name('ref_from_yyyy').send_keys(year)
    From_month = driver.find_element_by_name('ref_from_mm').send_keys(month)
    From_day = driver.find_element_by_name('ref_from_dd').send_keys(day)

    Search = driver.find_element_by_name('ACT_search').click()
    Download_csv = driver.find_element_by_id('csvlink').click()


def read_data(input_csv):
    csv_data = []
    with open(input_csv, newline='', encoding='shift-jis') as f:

        # pass head rows
        for (n, h) in enumerate(csv.DictReader(f), start=1):
            if n >= 5:
                break

        input_csv_header = ['約定日', '銘柄', '銘柄コード', '市場', '取引', '期限', '預り', '課税',
                            '約定数量', '約定単価', '手数料/諸経費等', '税額', '受渡日',
                            '受渡金額/決済損益']

        reader = csv.DictReader(f, input_csv_header)
        for row in reader:
            if item_code is None:
                # pass the exception rows of stock trade
                if row['取引'] != '株式現物買' and row['取引'] != '株式現物売':
                    continue
            else:
                if row['銘柄コード'] != item_code or (row['取引'] != '株式現物買' and row['取引'] != '株式現物売'):
                    continue

            csv_data.append(row)

    return csv_data


def calculate_data(csv_data):
    output_data = []
    for i, row in enumerate(csv_data):
        amount = 0
        price = 0
        for j in range(i + 1, len(csv_data)):
            if row['銘柄コード'] == csv_data[j]['銘柄コード']:
                brand = csv_data[j]['銘柄']
                brand_code = csv_data[j]['銘柄コード']

                if row['取引'] == '株式現物買':
                    sell_day = csv_data[j]['約定日']
                    buy_day = row['約定日']
                    sell_price = csv_data[j]['約定単価']
                    buy_price = row['約定単価']
                    sell_amount = csv_data[j]['約定数量']
                    buy_amount = row['約定数量']

                    if amount == 0:
                        amount = int(buy_amount) - int(sell_amount)
                        price = float(csv_data[j]['受渡金額/決済損益']) - float(row['受渡金額/決済損益'])
                    else:
                        amount -= int(sell_amount)
                        price += float(csv_data[j]['受渡金額/決済損益'])

                    if amount == 0:
                        item = {'現買日': buy_day,
                                '現売日': sell_day,
                                '銘柄': brand,
                                '銘柄コード': brand_code,
                                '購入数量': buy_amount,
                                '現買単価': buy_price,
                                '現売単価': sell_price,
                                '決済損益': price}

                else:
                    buy_day = csv_data[j]['約定日']
                    sell_day = row['約定日']
                    buy_price = csv_data[j]['約定単価']
                    sell_price = row['約定単価']
                    buy_amount = csv_data[j]['約定数量']
                    sell_amount = row['約定数量']

                    if amount == 0:
                        amount = int(buy_amount) - int(sell_amount)
                        price = float(row['受渡金額/決済損益']) - float(csv_data[j]['受渡金額/決済損益'])
                    else:
                        amount += int(buy_amount)
                        price -= float(csv_data[j]['受渡金額/決済損益'])

                    if amount == 0:
                        item = {'現買日': buy_day,
                                '現売日': sell_day,
                                '銘柄': brand,
                                '銘柄コード': brand_code,
                                '購入数量': buy_amount,
                                '現買単価': buy_price,
                                '現売単価': sell_price,
                                '決済損益': price}

                if amount == 0:
                    csv_data.pop(j)
                    output_data.append(item)
                    break

    return output_data


def write_data(output_data):
    output_csv = 'output.csv'
    output_csv_header = ['現買日', '現売日', '銘柄', '銘柄コード', '購入数量', '現買単価',
                        '現売単価', '決済損益']

    with open(output_csv, 'w', newline='', encoding='utf-8') as f:
        writer = csv.DictWriter(f, fieldnames=output_csv_header)
        writer.writeheader()
        total = 0
        for row in output_data:
            writer.writerow(row)
            total += float(row['決済損益'])
        print('\"total record: {}'.format(len(output_data)))
        print('total gain/loss: {}'.format(total))

        top_list = {}
        top_list = sorted(output_data, key=lambda x: x['決済損益'], reverse=True)
        bottom_list = {}
        bottom_list = sorted(output_data, key=lambda x: x['決済損益'])

        print('\n=TOP5=')
        for i in range(5 if len(top_list) >= 5 else len(top_list)):
            print(top_list[i])
        print('\n=BOTTOM5=')
        for i in range(5 if len(bottom_list) >= 5 else len(bottom_list)):
            print(bottom_list[i])
        # quotation
        print('\"')


def main():
    # setting folder for downloading
    downloadsFilePath = '.\\'
    options = ChromeOptions()
    prefs = {
                "profile.default_content_settings.popups": 1,
                "download.default_directory": 
                        os.path.abspath(downloadsFilePath) + r"\\",
                "directory_upgrade": True
            }
    options.add_experimental_option("prefs", prefs)

    driver = webdriver.Chrome(executable_path=r'./chromedriver.exe', options=options)
    driver.implicitly_wait(WAIT_TIME)

    login(driver)

    Account = driver.find_element_by_xpath('//a[img/@title="口座管理"]').click()

    # download csv file from 2021/01/01
    download_csvfile(driver, '2021', '01', '01')
    time.sleep(WAIT_TIME)

    # get the latest csv file name
    filename = None
    if len(os.listdir(downloadsFilePath)) != 0:
        filename = max([downloadsFilePath + '\\'+ f for f in os.listdir(downloadsFilePath) if f.endswith('.csv')], key=os.path.getctime)

    driver.close()

    csv_data = read_data(filename)

    output_data = calculate_data(csv_data)

    write_data(output_data)


if __name__== '__main__':
    main()

これからやってみること

  • 合計決済損益とトップ5、ワースト5を、毎日自分のメールアドレスに送信するようにサーバーに設定すれば、毎日自動的にトレード状況をチェックできてうれしいかも