November 25, 2023; Updated on

Python Scripting to Assist with Day Trading on Margin using Hyper SBI 2

In discretionary day trading of Japanese stocks, I trade on margin using a market order for immediacy. Previously, I used a spreadsheet to calculate the maximum number of shares I could order. However, it did not link to my cash balance in real time. Additionally, I noticed repetitive operations occurring in the Hyper SBI 2 trading software. In this post, I will discuss how to automate these processes using Python libraries.

Save Customer Margin Ratios and Previous Market Data

SBI Securities’ customer margin ratios are generally 31%. However, they regulate ratios between 51% and 71% for some stocks. To quickly calculate a maximum number of shares, save these ratios from the Stocks Subject to Margin Regulations page beforehand. Use pandas to retrieve and minimize them as follows:

import chardet
import pandas as pd
import requests

customer_margin_ratio_url = (
    'https://search.sbisec.co.jp/v2/popwin/attention/stock/margin_M29.html')
symbol_header = 'コード'
regulation_header = '規制内容'
headers = ('銘柄', 'コード', '建玉', '信用取引区分', '規制内容')
customer_margin_ratio_string = '委託保証金率'

# Extract tables containing the 'regulation_header' string.
response = requests.get(customer_margin_ratio_url)
encoding = chardet.detect(response.content)['encoding']
dfs = pd.read_html(response.content, match=regulation_header, flavor='lxml',
                   header=0, encoding=encoding)

# Select the table whose header matches the 'headers' tuple, and then extract
# the 'symbol_header' and 'regulation_header' columns.
for index, df in enumerate(dfs):
    if tuple(df.columns.values) == headers:
        df = dfs[index][[symbol_header, regulation_header]]
        break

# Extract the rows containing the 'customer_margin_ratio_string' string.
df = df[df[regulation_header].str.contains(customer_margin_ratio_string)]
df[regulation_header] = df[regulation_header].replace(
    '.*' + customer_margin_ratio_string + r'(\d+).*', r'0.\1', regex=True)

df.to_csv('customer_margin_ratios.csv', header=False, index=False)

Additionally, a market order requires buying power to purchase stocks at the upper price limit, not the current price. The Tokyo Stock Exchange sets upper price limits 20-30% higher than the previous closing prices. Save these closing prices from the Most Active Stocks Today page as described above. The date of these closing prices is determined using the Market Holidays page as follows:

import pandas as pd

market_holiday_url = (
    'https://www.jpx.co.jp/corporate/about-jpx/calendar/index.html')
date_header = '日付'
date_format = '%Y/%m/%d'

dfs = pd.read_html(market_holiday_url, match=date_header)
market_holidays = pd.concat(dfs, ignore_index=True)

# Go back until the day before is no longer a holiday above or a weekend.
previous_date = pd.Timestamp.now() - pd.Timedelta(days=1)
while (market_holidays[date_header].str.contains(
        previous_date.strftime(date_format)).any()
       or previous_date.weekday() == 5 or previous_date.weekday() == 6):
    previous_date -= pd.Timedelta(days=1)

print(previous_date)

Obtain Symbol from Window Title of Hyper SBI 2

Perform the following processes for each trade. First, to identify the stock and determine its customer margin ratio and price limit, obtain the symbol from the window title of Hyper SBI 2 using pywin32, which accesses Windows APIs.

import re

import win32gui

title_regex = '^個別銘柄\s.*\((\d{4})\)$'

# Define a class consisting of a callback function and its result.
class Trade:
    def __init__(self):
        self.symbol = ''

    def get_symbol(self, hwnd, title_regex):
        matched = re.search(title_regex, str(win32gui.GetWindowText(hwnd)))
        if matched:
            self.symbol = matched.group(1)
            return

trade = Trade()
win32gui.EnumWindows(trade.get_symbol, title_regex)

print(trade.symbol)

Recognize Cash Balance on Hyper SBI 2

Next, to recognize the cash balance on the “Summary” window of Hyper SBI 2, show the window using pywin32 and invoke Tesseract using pytesseract.

import pyautogui
import pytesseract

x, y, width, height = 1000, 1000, 150, 20

image = pyautogui.screenshot(region=(x, y, width, height))

# To recognize expressions such as '1,500.5 - 2,500.5', assume that prices are
# a single line separated by space.
separated_prices = pytesseract.image_to_string(
    image, config='-c tessedit_char_whitelist=\ .,0123456789 --psm 7')
cash_balance = int(separated_prices.split(' ')[-1].replace(',', ''))

print(cash_balance)

Calculate Maximum Number of Shares for Market Order on Margin Trading

Using the customer margin ratio, price limit, and cash balance obtained above, the maximum number of shares for a market order on margin trading is:

\[ \left\lfloor\frac{\yen cash\ balance}{customer\ margin\ ratio \times \yen price\ limit \times trading\ unit}\right\rfloor \times trading\ unit. \]

Automate Manipulation of Hyper SBI 2

Finally, show the other necessary windows of Hyper SBI 2 using pywin32. Then, manipulate their widgets and enter the maximum number of shares calculated in the previous section using pyautogui, which controls the mouse and keyboard.

Python Script Example

Combining the above processes, you can automate operating parts of discretionary day trading of stocks on margin. In a real-world application, I have published the trading_assistant.py Python script on GitHub. You can see this script in action in the screencast at the beginning of this post.

No comments:

Post a Comment