0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

立花証券・e支店・APIのラッパー

Last updated at Posted at 2025-04-13

e支店のAPIはクセが強めで、ぜんぜんリーダブルではないんですが、ユーザー向けツールの拡張的位置づけの某kabuステと違って、自社のサービス向けにしっかりと開発されている印象です。
抽象度を上げるラッパーさえ書いてしまえば、なんてことはない。

しかし、IssueもほったらかしのkabuステのAPIは今後どうなるんでしょうか。
一般信用の貸借銘柄が豊富なのは魅力なので、ぜひ頑張ってほしい所です。

python ebranchapi/__init__.py
import requests
import datetime as dt
import json
from ebranchapi import get_market_price

class Context(object):
    def __init__(
        self,
        base_url=None,
        user_id=None,
        password=None,
    ):
        self.base_url = base_url
        self.user_id = user_id
        self.password = password
        self.request_no = 1
        self.session_info = None
        self.mapping = {
            'xLISS': '所属',
            'pDPP': '現在値',
            'tDPP:T': '現在値時刻',
            'pDPG': '現値前値比較',
            'pDYWP': '前日比',
            'pDYRP': '騰落率',
            'pDOP': '始値',
            'tDOP:T': '始値時刻',
            'pDHP': '高値',
            'tDHP:T': '高値時刻',
            'pDLP': '安値',
            'tDLP:T': '安値時刻',
            'pDV': '出来高',
            'pQAS': '売気配値種類',
            'pQAP': '売気配値',
            'pAV': '売気配数量',
            'pQBS': '買気配値種類',
            'pQBP': '買気配値',
            'pBV': '買気配数量',
            'xDVES': '配当落銘柄区分',
            'xDCFS': '不連続要因銘柄区分',
            'pDHF': '日通し高値フラグ',
            'pDLF': '日通し安値フラグ',
            'pDJ': '売買代金',
            'pAAV': '売数量(成行)',
            'pABV': '買数量(成行)',
            'pQOV': '売-OVER',
            'pGAV10': '売-10-数量',
            'pGAP10': '売-10-値段',
            'pGAV9': '売-9-数量',
            'pGAP9': '売-9-値段',
            'pGAV8': '売-8-数量',
            'pGAP8': '売-8-値段',
            'pGAV7': '売-7-数量',
            'pGAP7': '売-7-値段',
            'pGAV6': '売-6-数量',
            'pGAP6': '売-6-値段',
            'pGAV5': '売-5-数量',
            'pGAP5': '売-5-値段',
            'pGAV4': '売-4-数量',
            'pGAP4': '売-4-値段',
            'pGAV3': '売-3-数量',
            'pGAP3': '売-3-値段',
            'pGAV2': '売-2-数量',
            'pGAP2': '売-2-値段',
            'pGAV1': '売-1-数量',
            'pGAP1': '売-1-値段',
            'pGBV1': '買-1-数量',
            'pGBP1': '買-1-値段',
            'pGBV2': '買-2-数量',
            'pGBP2': '買-2-値段',
            'pGBV3': '買-3-数量',
            'pGBP3': '買-3-値段',
            'pGBV4': '買-4-数量',
            'pGBP4': '買-4-値段',
            'pGBV5': '買-5-数量',
            'pGBP5': '買-5-値段',
            'pGBV6': '買-6-数量',
            'pGBP6': '買-6-値段',
            'pGBV7': '買-7-数量',
            'pGBP7': '買-7-値段',
            'pGBV8': '買-8-数量',
            'pGBP8': '買-8-値段',
            'pGBV9': '買-9-数量',
            'pGBP9': '買-9-値段',
            'pGBV10': '買-10-数量',
            'pGBP10': '買-10-値段',
            'pQUV': '買-UNDER',
            'pVWAP': 'VWAP',
            'pPRP': '前日終値'}
        
        self.get_market_price = get_market_price.EntitySpec(self)
        # 以下、必要なエンドポイントを開発次第、追加していく
        # 今んとこは get_market_price だけ
    
    def req(self, url, params, headers=None):
        params['p_no'] = str(self.request_no)
        params['p_sd_date'] = dt.datetime.now().strftime('%Y.%m.%d-%H:%M:%S.%f')[:-3]
        params['sJsonOfmt'] = '5'
        params = json.dumps(params, ensure_ascii=False)
        url = f"{url}?{params}"
        res = requests.get(url, headers=headers)
        res.encoding = 'shift-jis'
        content = res.text
        self.request_no += 1
        return json.loads(content)

    def login(self):
        params = {
            'sCLMID': 'CLMAuthLoginRequest',
            'sUserId': self.user_id,
            'sPassword': self.password,
        }
        res = self.req(f"{self.base_url}/auth/", params)

        if int(res.get('p_errno', -1)) == 0 and int(res.get('sResultCode', -1)) == 0:
            if res.get('sUrlRequest'):
                self.session_info = {
                    'sUrlRequest': res.get('sUrlRequest'),
                    'sUrlMaster': res.get('sUrlMaster'),
                    'sUrlPrice': res.get('sUrlPrice'),
                    'sUrlEvent': res.get('sUrlEvent'),
                    'sZyoutoekiKazeiC': res.get('sZyoutoekiKazeiC')
                }
            else:
                raise Exception("契約締結前書面が未読です。ブラウザーで確認してください。")
        else:
            raise Exception(f"ログイン失敗: {res.get('p_err')}, コード: {res.get('sResultCode')}")

    def logout(self):
        if not self.session_info:
            return 
            
        params = {'sCLMID': 'CLMAuthLogoutRequest'}
        
        res = self.req(self.session_info['sUrlRequest'], params)
        if int(res.get('sResultCode', -1)) == 0:
            self.session_info = None
            return
        else:
            raise Exception(f"ログアウト失敗: {res.get('p_err')}, コード: {res.get('sResultCode')}")
        
    def code_to_name(self, code):
        return self.mapping.get(code, code)
python ebranchapi/get_market_price.py
class EntitySpec(object):
    def __init__(self, ctx):
        self.ctx = ctx

    def __call__(self, **kwargs):
        symbols = kwargs.get("symbols")
        columns = kwargs.get("columns")
        params = {
            'sCLMID': 'CLMMfdsGetMarketPrice',
            'sTargetIssueCode': ','.join(symbols),
            'sTargetColumn': ','.join(columns),
        }
        res = self.ctx.req(
            self.ctx.session_info['sUrlPrice'],
            params)
        res = res.get('aCLMMfdsMarketPrice', [])
        return res

利用するときは、こんな感じ

import ebranchapi
from common import const

api = ebranchapi.Context(
    base_url=const.BASE_URL, # 最後の/は含めない
    user_id=const.EBRANCH_USER_ID,
    password=const.EBRANCH_PASS,
)

api.login()

symbols = ["7203", "6758", "9984"]
columns = [ "pQAP", # 売気配値
            "pQBP", # 買気配値
            'pPRP', # 前日終値
            ]
data = api.get_market_price(symbols=symbols, columns=columns)

# => [
# {'sIssueCode': '7203', 'pQAP': '2720.0', 'pQBP': '2719.5', 'pPRP': '2365.5'},
# {'sIssueCode': '6758', 'pQAP': '3500', 'pQBP': '3499', 'pPRP': '3107'}, 
# {'sIssueCode': '9984', 'pQAP': '7070', 'pQBP': '7070', 'pPRP': '6070'}]

0
1
1

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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?