2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-04-16

やってみたこと

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を、毎日自分のメールアドレスに送信するようにサーバーに設定すれば、毎日自動的にトレード状況をチェックできてうれしいかも
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?