Bybit API × Python 自動売買の始め方
pybit入門・APIキー発行から
テストネット接続まで完全ガイド

BybitのV5 APIは、現物・無期限先物・先物・オプションを1つの仕様に統合した非常に扱いやすいAPIです。この記事では公式Python SDK pybit の導入から、事故を起こさないAPIキーの権限設計、テストネット・デモトレードへの接続、残高とティッカーの取得、そしてSDKを使わない署名の自作までを、コピペで動くサンプルコード15本で解説します。

確認日
2026-07-30
API バージョン
Bybit V5
Python
3.10 以上
pybit
5.17.0

※ Bybit V5は機能追加のペースが速いAPIです。パラメータの最終的な正解は必ず公式ドキュメントで確認してください。本記事のコードはすべてテストネットで動作確認しています。

目次

  1. なぜBybit V5 APIなのか|MT4/MT5のEAとの決定的な違い
  2. 環境構築|venvとrequirements.txt
  3. まず動かす|8行でBTC価格を取得する
  4. APIキーの発行と権限設計|出金権限を絶対に付けない理由
  5. 3つの環境を理解する|mainnet / testnet / demo trading
  6. キー管理コード|.envとCredentialsクラス
  7. 環境切替クライアントの実装(サンプル4)
  8. 疎通確認と時刻ズレ検出(サンプル5)
  9. 全銘柄ティッカーをDataFrame化してスクリーニング(サンプル6)
  10. 統合口座(UNIFIED)の残高を読む(サンプル7)
  11. 銘柄仕様の取得とDecimal丸め(サンプル8)
  12. SDKを使わない|requestsで署名を自作する(サンプル9・10)
  13. V5レスポンス構造とretCodeの読み方
  14. よくあるエラーと対処
  15. 実運用に進む前に必ず押さえる5つのこと
  16. よくある疑問Q&A

なぜBybit V5 APIなのか|MT4/MT5のEAとの決定的な違い

当サイトではMT4/MT5のEA(Expert Advisor)を配布していますが、仮想通貨の自動売買では取引所APIを直接叩く方式が主流です。両者の違いを整理しておきます。

観点 MT4/MT5 + EA(MQL) Bybit V5 API + Python
言語 MQL4 / MQL5(C++系) Python(pandas・scipyがそのまま使える)
実行環境 Windows + MT4/MT5の常時起動が必須 Linux VPSでプロセスを回すだけ
データ取得 ブローカー配信の足に依存 板・ティック・OI・資金調達率まで取得可
統計・機械学習 実質困難(外部DLL連携が必要) statsmodels / scikit-learn を直接利用
リアルタイム受信 OnTick()イベント WebSocketで板差分・約定を購読
難易度 EAを入れるだけなら簡単 注文管理・例外処理を自分で書く必要あり

Pythonの自由度は圧倒的ですが、代わりに「MT4が面倒を見てくれていた部分」を全部自分で書く必要があります。具体的には、通信エラーのリトライ、二重発注の防止、レート制限の遵守、bot再起動時のポジション同期などです。このシリーズはそこを1本ずつ潰していく構成になっています。

V5 APIの「統合」が何を意味するか

Bybit V5は、以前はバラバラだった現物・デリバティブ・オプションのAPIを1仕様に統合したものです。実装上は category というパラメータ1つで対象商品を切り替えます。

category 対象 代表シンボル 数量の単位
linear USDT/USDC無期限・USDT先物 BTCUSDT BTC(基軸通貨)
inverse コイン建て無期限・先物 BTCUSD USD(枚数)
spot 現物 BTCUSDT BTC または USDT
option オプション BTC-31JUL26-90000-C コンタクト数
最初につまずくポイント

category の指定を間違えると「シンボルが存在しない」という一見わけのわからないエラーになります。BTCUSDT は linear と spot の両方に存在し、同じシンボル名で別の商品です。この設計は記事03で徹底的に扱います。

環境構築|venvとrequirements.txt

pybit 5.17.0 はPython 3.10以上が必要です。まずプロジェクトディレクトリを作り、仮想環境を切ります。

シェル(Windows / macOS / Linux)サンプル1
mkdir bybit-bot
cd bybit-bot

# 仮想環境の作成
python -m venv .venv

# 有効化(Windows PowerShell)
.venv\Scripts\Activate.ps1
# 有効化(macOS / Linux)
source .venv/bin/activate

python --version        # 3.10 以上であることを確認
pip install -U pip
pip install -r requirements.txt
requirements.txtサンプル2
# Bybit公式Python SDK(HTTP + WebSocketの両方を含む)
pybit>=5.17.0

# データ処理
pandas>=2.2
pyarrow>=17.0          # Parquet保存用(記事07で使用)

# 設定・通信
python-dotenv>=1.0     # .envからAPIキーを読む
requests>=2.32         # 署名を自作する場合(サンプル10)

# 開発補助
rich>=13.7             # CLIでの表示を見やすくする

pybit は Bybit の従業員が保守している公式SDKで、V5のRESTとWebSocketの両方をカバーしています。ccxt という汎用ライブラリもありますが、V5固有のパラメータ(tpslMode、positionIdx、orderFilter など)を細かく制御したい場合は pybit か自作クライアントのほうが素直です。

.gitignore を最初に作る

APIキーをGitHubに push する事故は本当によく起きます。コードを1行も書く前に .gitignore に .venv/ と .env を書いてください。公開リポジトリに漏れたキーは、数分で自動収集ボットに拾われます。

まず動かす|8行でBTC価格を取得する

Bybitの公開エンドポイント(Market系)はAPIキー不要です。まずキーの発行を後回しにして、通信できることを確認しましょう。

hello_bybit.pyサンプル3
# 本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
from pybit.unified_trading import HTTP

session = HTTP(testnet=True)          # Market系エンドポイントはAPIキー不要
res = session.get_tickers(category="linear", symbol="BTCUSDT")

t = res["result"]["list"][0]
print(f"シンボル    : {t['symbol']}")
print(f"最終価格    : {t['lastPrice']}")
print(f"24h変化率   : {float(t['price24hPcnt']) * 100:+.2f} %")
print(f"資金調達率  : {float(t['fundingRate']) * 100:+.4f} %")
print(f"未決済建玉  : {t['openInterest']}")
実行結果(例)出力
シンボル    : BTCUSDT
最終価格    : 118342.50
24h変化率   : +1.83 %
資金調達率  : +0.0100 %
未決済建玉  : 58234.117

これが動けばネットワーク面は問題ありません。ここから先、残高照会・発注・ポジション取得にはAPIキーと署名が必要になります。

APIキーの発行と権限設計|出金権限を絶対に付けない理由

Bybitのアカウント設定からAPIキーを発行します。キーには2種類あります。

方式 秘密鍵の管理 署名アルゴリズム 向いている用途
システム生成 Bybitが生成し、発行時に1回だけ表示 HMAC-SHA256 個人bot(本記事はこちら)
自己生成(RSA) 自分でRSA鍵ペアを作り公開鍵だけ登録。秘密鍵はBybitに渡らない RSA-SHA256 秘密鍵を外部に出したくない運用

権限(パーミッション)の設計

ここが最重要です。1つのキーに全権限を付けるのは設計ミスです。用途別に分けます。

キーの用途 Read Trade(発注) Transfer(振替) Withdrawal(出金)
データ収集・分析 ○ × × ×
売買bot ○ ○ × ×
資金配分bot ○ × ○ ×
監視ダッシュボード ○ × × ×
出金権限は絶対に付けない

bot用のAPIキーに出金権限を付ける理由はひとつもありません。VPSが侵害されても、ソースをGitHubに誤commitしても、出金権限がなければ資金は外部へ出せません(最悪でも「変な取引をされる」で止まります)。出金権限が付いたキーの漏洩は、取り返しがつきません。

同様に、バックテストやデータ収集用のスクリプトにはRead-Onlyキーを渡してください。売買権限のあるキーを分析用Jupyterノートブックで使うと、セルの誤実行で発注してしまいます。

IPアドレス制限を必ず設定する

APIキーには接続元IPアドレスの制限を掛けられます。VPSで運用する場合はVPSのグローバルIPを登録してください。キーが漏れても、そのIP以外からは使えません。

なお、IPアドレスを紐付けていないキーには有効期限が設定される仕様になっています。期限切れに気づかずbotが止まる事故を避けるため、発行時に管理画面で有効期限を確認し、カレンダーに更新日を入れておくことを強く推奨します(期限のルールは変更される可能性があるため、必ず管理画面の表示を確認してください)。

キー発行の実務チェックリスト

3つの環境を理解する|mainnet / testnet / demo trading

Bybitには本番以外に2種類の練習環境があり、これを混同すると「キーが通らない」「板が薄すぎて検証にならない」といった問題にぶつかります。

環境 REST ベースURL アカウント 板・価格 向いている用途
mainnet api.bybit.com
(別名 api.bytick.com)
本番 本物 本番運用
testnet api-testnet.bybit.com testnet専用に別途登録 薄い・価格が乖離 APIの疎通・パラメータ確認
demo trading api-demo.bybit.com 本番アカウント内の別UID 本番と同じ 戦略ロジックの実戦テスト

使い分けの結論はこうです。

demo trading のAPIキーは専用のものが必要

demo trading のキーは、本番アカウントにログインした状態でデモトレード画面に切り替えてから発行します(デモは独立したUIDを持ちます)。本番キーを api-demo.bybit.com に投げても通りませんし、逆も同様です。また、testnetサイト側でデモトレードのキーを作る意味はないため、Bybitのドキュメントでも非推奨とされています。

WebSocketも環境ごとに別で、demoのprivateストリームは wss://stream-demo.bybit.com、公開データは本番の wss://stream.bybit.com を使います(記事26・27で扱います)。

なお日本国内向けには api.manepa.jp のような地域別ドメインも用意されています。自分のアカウントがどのエンティティに属しているかで接続先が変わる場合があるため、キーが正しいのに認証エラーが出るときは接続先ドメインを疑ってください。

demo trading に仮想資金を入れる

デモ口座への資金投入もAPIから行えます。1リクエストあたりの上限は BTC 15 / ETH 200 / USDT・USDC 各 100,000 です。

apply_demo_money.pydemo環境限定
# demo trading 口座に仮想資金を投入する(api-demo.bybit.com 専用)
from pybit.unified_trading import HTTP

session = HTTP(demo=True, api_key="DEMO_KEY", api_secret="DEMO_SECRET")

res = session._submit_request(
    method="POST",
    path=f"{session.endpoint}/v5/account/demo-apply-money",
    query={"adjustType": 0, "utaDemoApplyMoney": [{"coin": "USDT", "amountStr": "100000"}]},
    auth=True,
)
print(res["retCode"], res["retMsg"])

pybit に専用メソッドが用意されていない場合は上記のように内部の _submit_request() を使えますが、私有メソッドに依存するのは望ましくありません。サンプル10の自作クライアントを使えばこうした未実装エンドポイントも素直に叩けます。

キー管理コード|.envとCredentialsクラス

環境ごとにキーが違うので、.env にプレフィックス付きで並べて、コードから環境名で引く形にします。

.env(絶対にコミットしない)設定
# 既定の接続先: testnet / demo / mainnet
BYBIT_ENV=testnet

# testnet.bybit.com で発行したキー
BYBIT_TESTNET_API_KEY=xxxxxxxxxxxxxxxxxxxx
BYBIT_TESTNET_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# デモトレード画面で発行したキー
BYBIT_DEMO_API_KEY=
BYBIT_DEMO_API_SECRET=

# 本番キー(出金権限なし・IP制限あり)
BYBIT_MAINNET_API_KEY=
BYBIT_MAINNET_API_SECRET=
config.pyサンプル4a
"""config.py — 環境ごとのAPIキーを型安全に読み込む
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

import os
from dataclasses import dataclass
from enum import Enum
from pathlib import Path

from dotenv import load_dotenv

load_dotenv(Path(__file__).with_name(".env"))


class Env(str, Enum):
    TESTNET = "testnet"
    DEMO = "demo"
    MAINNET = "mainnet"


_PREFIX = {
    Env.TESTNET: "BYBIT_TESTNET",
    Env.DEMO: "BYBIT_DEMO",
    Env.MAINNET: "BYBIT_MAINNET",
}

# pybit に渡すフラグと、自作クライアント用のベースURL
REST_BASE = {
    Env.TESTNET: "https://api-testnet.bybit.com",
    Env.DEMO: "https://api-demo.bybit.com",
    Env.MAINNET: "https://api.bybit.com",
}


@dataclass(frozen=True)
class Credentials:
    env: Env
    api_key: str
    api_secret: str

    @property
    def testnet(self) -> bool:
        return self.env is Env.TESTNET

    @property
    def demo(self) -> bool:
        return self.env is Env.DEMO

    @property
    def base_url(self) -> str:
        return REST_BASE[self.env]

    def masked(self) -> str:
        """ログ出力用。キーの先頭4文字だけ見せる。"""
        return f"{self.env.value}:{self.api_key[:4]}****"


def load_credentials(env: str | None = None) -> Credentials:
    resolved = Env(env or os.getenv("BYBIT_ENV", "testnet"))
    prefix = _PREFIX[resolved]

    key = os.getenv(f"{prefix}_API_KEY", "").strip()
    secret = os.getenv(f"{prefix}_API_SECRET", "").strip()
    if not key or not secret:
        raise RuntimeError(
            f"{prefix}_API_KEY / {prefix}_API_SECRET が .env に設定されていません "
            f"(BYBIT_ENV={resolved.value})"
        )
    return Credentials(env=resolved, api_key=key, api_secret=secret)

masked() を用意しているのは、ログにAPIキーを平文で出さないためです。障害調査時に「どのキーで動いていたか」は知りたいが、キー本体はログに残したくない。この癖は最初から付けておくと後で助かります(監視・ロギングの設計は記事39)。

環境切替クライアントの実装

Credentials から pybit の HTTP セッションを組み立てるファクトリを作ります。本番接続時だけ明示的な確認を要求するガードも入れておきます。

client.pyサンプル4b
"""client.py — pybitセッションのファクトリと本番誤爆ガード
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

import os
from dataclasses import dataclass

from pybit.unified_trading import HTTP

from config import Credentials, Env, load_credentials


@dataclass(frozen=True)
class BybitClient:
    """環境情報を保持したまま持ち回せるクライアント。"""

    env: Env
    http: HTTP
    cred: Credentials

    @property
    def is_live(self) -> bool:
        return self.env is Env.MAINNET


def make_client(env: str | None = None, *, allow_mainnet: bool = False) -> BybitClient:
    cred = load_credentials(env)

    # --- 本番誤爆ガード -------------------------------------------------
    # 引数で明示許可し、かつ環境変数 BYBIT_ALLOW_LIVE=1 が立っていないと
    # mainnetには接続させない。二重の鍵をかけておく。
    if cred.env is Env.MAINNET:
        if not allow_mainnet:
            raise PermissionError(
                "mainnet接続には make_client(..., allow_mainnet=True) が必要です"
            )
        if os.getenv("BYBIT_ALLOW_LIVE") != "1":
            raise PermissionError(
                "mainnet接続には環境変数 BYBIT_ALLOW_LIVE=1 が必要です"
            )
    # -------------------------------------------------------------------

    http = HTTP(
        testnet=cred.testnet,
        demo=cred.demo,
        api_key=cred.api_key,
        api_secret=cred.api_secret,
        recv_window=5000,   # 署名の有効時間(ms)。時計がズレると10002が出る
        timeout=10,         # 秒
        max_retries=3,      # pybit内蔵のリトライ回数
        retry_delay=3,      # 秒
        log_requests=False, # デバッグ時のみTrue(キーはログに出ない)
    )
    return BybitClient(env=cred.env, http=http, cred=cred)


if __name__ == "__main__":
    c = make_client()
    print(f"接続先: {c.cred.masked()}  endpoint={c.http.endpoint}")
なぜガードを二重にするのか

BYBIT_ENV=mainnet を .env に書いたまま検証スクリプトを実行して本番に発注してしまう、というのは実際に頻発する事故です。「コード側の明示フラグ」と「環境変数」の両方が揃わないと本番に繋がらない設計にしておけば、片方を忘れても事故になりません。これはコストゼロの保険です。

疎通確認と時刻ズレ検出

認証付きリクエストを初めて投げる前に、ローカル時計とBybitサーバー時刻のズレを測ってください。V5の署名にはタイムスタンプが含まれ、recv_window(既定5000ms)を超えてズレているとすべてのリクエストが retCode=10002 で落ちます。「キーは正しいのに認証が通らない」の犯人は、ほぼこれです。

check_connection.pyサンプル5
"""check_connection.py — 疎通確認・時刻ズレ検出・権限確認
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

import time

from pybit.unified_trading import HTTP

from client import make_client

RECV_WINDOW_MS = 5000


def check_clock_skew(http: HTTP, samples: int = 5) -> float:
    """サーバー時刻とローカル時刻の差(ms)を返す。正なら自分の時計が遅れている。"""
    skews, rtts = [], []
    for _ in range(samples):
        t0 = time.time()
        res = http.get_server_time()
        t1 = time.time()

        # timeNano(ns) のほうが精度が高い
        server_ms = int(res["result"]["timeNano"]) / 1_000_000
        local_ms = (t0 + t1) / 2 * 1000     # 往復の中点をローカル時刻とみなす
        skews.append(server_ms - local_ms)
        rtts.append((t1 - t0) * 1000)
        time.sleep(0.2)

    skew = sorted(skews)[len(skews) // 2]   # 中央値でRTTのばらつきを吸収
    rtt = sorted(rtts)[len(rtts) // 2]

    print(f"  RTT(中央値)   : {rtt:8.1f} ms")
    print(f"  時刻ズレ      : {skew:+8.1f} ms")

    if abs(skew) > RECV_WINDOW_MS * 0.5:
        print("  [警告] ズレが大きすぎます。retCode=10002 の原因になります。")
        print("         Windows : w32tm /resync")
        print("         Linux   : sudo chronyc makestep")
    return skew


def check_permissions(http: HTTP) -> None:
    """キーの権限・有効期限・IP制限を確認する。"""
    res = http.get_api_key_information()
    info = res["result"]
    print(f"  キー種別      : {'RSA' if info.get('type') == 2 else 'HMAC'}")
    print(f"  有効期限      : {info.get('expiredAt') or '(無期限)'}")
    print(f"  IP制限        : {info.get('ips') or '(なし)'}")
    print(f"  読み取り専用  : {'はい' if info.get('readOnly') == 1 else 'いいえ'}")
    perms = {k: v for k, v in (info.get("permissions") or {}).items() if v}
    print(f"  権限          : {perms}")


def main() -> None:
    c = make_client()
    print(f"[1] 接続先 {c.cred.masked()}  {c.http.endpoint}")

    print("[2] 時刻同期チェック")
    check_clock_skew(c.http)

    print("[3] APIキー権限チェック")
    check_permissions(c.http)

    print("[4] 残高取得(認証テスト)")
    res = c.http.get_wallet_balance(accountType="UNIFIED")
    print(f"  retCode={res['retCode']} retMsg={res['retMsg']}")
    print("  OK: 認証付きリクエストが通りました")


if __name__ == "__main__":
    main()
実行結果(例)出力
[1] 接続先 testnet:AbCd****  https://api-testnet.bybit.com
[2] 時刻同期チェック
  RTT(中央値)   :    182.4 ms
  時刻ズレ      :    -12.7 ms
[3] APIキー権限チェック
  キー種別      : HMAC
  有効期限      : 1786579200000
  IP制限        : ['203.0.113.10']
  読み取り専用  : いいえ
  権限          : {'Wallet': ['AccountTransfer'], 'ContractTrade': ['Order', 'Position']}
[4] 残高取得(認証テスト)
  retCode=0 retMsg=OK
  OK: 認証付きリクエストが通りました
時刻同期はVPSでも必須

クラウドVPSは時計が正確だと思われがちですが、コンテナや仮想化環境では平気で数秒ズレます。本番運用では chrony を入れて、さらに上記の check_clock_skew() を定期実行してズレをメトリクスとして監視してください(記事38・39)。

全銘柄ティッカーをDataFrame化してスクリーニング

get_tickers() は symbol を省略するとそのcategoryの全銘柄を1回で返します。Bybitのlinearは数百銘柄あるため、これだけで簡易スクリーナーが作れます。

ここで重要なのは、V5のレスポンスは数値もすべて文字列で返ってくるという点です。float() 変換を忘れて文字列比較になり「価格の大小判定がおかしい」というバグは初学者の定番です。

screener.pyサンプル6
"""screener.py — 全銘柄ティッカーをDataFrame化して流動性でスクリーニング
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

import pandas as pd
from pybit.unified_trading import HTTP

from client import make_client

# V5は数値も文字列で返るため、明示的に数値化する対象を列挙しておく
NUMERIC_COLS = [
    "lastPrice", "indexPrice", "markPrice", "prevPrice24h", "price24hPcnt",
    "highPrice24h", "lowPrice24h", "turnover24h", "volume24h",
    "openInterest", "openInterestValue", "fundingRate",
    "bid1Price", "bid1Size", "ask1Price", "ask1Size",
]


def fetch_tickers(http: HTTP, category: str = "linear") -> pd.DataFrame:
    res = http.get_tickers(category=category)
    if res["retCode"] != 0:
        raise RuntimeError(f"get_tickers失敗: {res['retCode']} {res['retMsg']}")

    df = pd.DataFrame(res["result"]["list"])
    for col in NUMERIC_COLS:
        if col in df.columns:
            df[col] = pd.to_numeric(df[col], errors="coerce")

    # 実効スプレッド(bps = 万分率)。執行コストの一次近似になる
    df["spread_bps"] = (df["ask1Price"] - df["bid1Price"]) / df["lastPrice"] * 10_000

    # 資金調達率の年率換算。※8時間ごと収受(1日3回)を仮定した概算。
    #   実際の収受間隔は銘柄ごとに異なる(instruments-infoのfundingInterval)。
    #   正確な計算は記事10で扱う。
    df["funding_apr_pct"] = df["fundingRate"] * 3 * 365 * 100

    df["chg24h_pct"] = df["price24hPcnt"] * 100
    return df


def screen_usdt_perp(df: pd.DataFrame, min_turnover_usd: float = 50_000_000) -> pd.DataFrame:
    """USDT無期限のうち、24h売買代金が閾値以上の銘柄を流動性順に返す。"""
    out = df[df["symbol"].str.endswith("USDT")].copy()
    out = out[out["turnover24h"] >= min_turnover_usd]
    out = out.sort_values("turnover24h", ascending=False)
    return out[[
        "symbol", "lastPrice", "chg24h_pct", "turnover24h",
        "spread_bps", "funding_apr_pct", "openInterestValue",
    ]].reset_index(drop=True)


if __name__ == "__main__":
    c = make_client()
    tickers = fetch_tickers(c.http, category="linear")
    print(f"取得銘柄数: {len(tickers)}")

    top = screen_usdt_perp(tickers)
    pd.set_option("display.width", 160)
    pd.set_option("display.float_format", lambda v: f"{v:,.4f}")
    print(top.head(15).to_string())

    # 資金調達率が高い=ロングが過熱している銘柄(記事35のアービトラージ候補)
    print("\n--- 資金調達率(年率)上位 ---")
    print(top.nlargest(10, "funding_apr_pct")[
        ["symbol", "funding_apr_pct", "turnover24h", "spread_bps"]
    ].to_string())

このコードは category="spot" に変えれば現物にもそのまま使えます(ただし現物には fundingRate や openInterest が存在しないため、該当列は欠損になります)。

スプレッド(bps)を見る癖をつける

アルトコインの無期限先物は、ボラティリティが高い代わりにスプレッドが数十bpsに開いていることがあります。往復で0.5%取られる銘柄で数時間の値幅を狙う戦略は、バックテストで勝っていても実運用では成立しません。銘柄選定の段階で spread_bps によるフィルタを入れておくと、後段の検証が現実的になります(記事12・31)。

統合口座(UNIFIED)の残高を読む

Bybitの統合取引口座(UTA: Unified Trading Account)では、現物・無期限・オプションで証拠金が共有されます。そのため残高レスポンスは「口座全体のサマリ」+「通貨ごとの明細」という2階層構造になっています。

wallet.pyサンプル7
"""wallet.py — 統合口座の残高とリスク指標を読む
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

from pybit.unified_trading import HTTP

from client import make_client


def f(value: str | None) -> float:
    """V5は「該当なし」を空文字で返すことがあるので安全に数値化する。"""
    if value is None or value == "":
        return 0.0
    return float(value)


def show_wallet(http: HTTP, account_type: str = "UNIFIED") -> dict:
    res = http.get_wallet_balance(accountType=account_type)
    if res["retCode"] != 0:
        raise RuntimeError(f"get_wallet_balance失敗: {res['retCode']} {res['retMsg']}")

    acct = res["result"]["list"][0]

    print("=== 口座サマリ (USD換算) ===")
    print(f"  総資産            : {f(acct['totalEquity']):>14,.2f}")
    print(f"  総証拠金残高      : {f(acct['totalMarginBalance']):>14,.2f}")
    print(f"  利用可能証拠金    : {f(acct['totalAvailableBalance']):>14,.2f}")
    print(f"  使用中(初期証拠金): {f(acct['totalInitialMargin']):>14,.2f}")
    print(f"  維持証拠金        : {f(acct['totalMaintenanceMargin']):>14,.2f}")
    print(f"  無期限の含み損益  : {f(acct['totalPerpUPL']):>+14,.2f}")

    # 口座維持率。1.0(100%)に近づくと強制決済が発生する
    mmr = f(acct.get("accountMMRate"))
    imr = f(acct.get("accountIMRate"))
    print(f"  口座維持率(MMR)   : {mmr * 100:>13.3f} %")
    print(f"  口座初期率(IMR)   : {imr * 100:>13.3f} %")
    if mmr > 0.5:
        print("  [警告] 維持率が50%を超えています。清算距離が近い状態です。")

    print("\n=== 通貨別明細 ===")
    print(f"  {'coin':<8}{'残高':>16}{'含み損益':>14}{'USD換算':>14}")
    for coin in acct["coin"]:
        bal = f(coin["walletBalance"])
        if bal == 0 and f(coin["unrealisedPnl"]) == 0:
            continue
        print(
            f"  {coin['coin']:<8}{bal:>16,.6f}"
            f"{f(coin['unrealisedPnl']):>+14,.2f}{f(coin['usdValue']):>14,.2f}"
        )
    return acct


if __name__ == "__main__":
    c = make_client()
    show_wallet(c.http)

ここで出てくる accountMMRate(口座維持率)は、リスク管理の中心になる指標です。この値が1.0に近づくと強制決済が発生します。清算価格の自前計算とストレステストは記事22で扱いますが、bot運用ではこの1つの数値を常時監視するだけでも生存率が大きく変わります。

accountType の指定

統合口座なら UNIFIED、旧来の通常口座(未アップグレード)なら CONTRACT を指定します。自分の口座種別が不明な場合は get_account_info() で確認できます。誤った accountType を渡すとパラメータエラー(10001)になります。

銘柄仕様の取得とDecimal丸め

発注に進む前に、絶対に避けて通れない処理があります。価格と数量の丸めです。

銘柄ごとに「価格の刻み幅(tickSize)」「数量の刻み幅(qtyStep)」「最小注文数量(minOrderQty)」が決まっており、これに合わない値を送ると発注が拒否されます。しかも float で計算すると 0.1 + 0.2 = 0.30000000000000004 のような誤差が出て、刻み幅に一致しなくなります。価格と数量は必ず Decimal で扱ってください。

symbol_rules.pyサンプル8
"""symbol_rules.py — 銘柄仕様の取得とDecimalによる丸め
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

from dataclasses import dataclass
from decimal import ROUND_DOWN, ROUND_HALF_UP, Decimal

from pybit.unified_trading import HTTP

from client import make_client


@dataclass(frozen=True)
class SymbolRules:
    symbol: str
    category: str
    tick_size: Decimal      # 価格の刻み幅
    qty_step: Decimal       # 数量の刻み幅
    min_qty: Decimal        # 最小注文数量
    max_qty: Decimal        # 最大注文数量(成行/指値で異なる場合あり)
    min_notional: Decimal   # 最小注文金額
    max_leverage: Decimal   # 最大レバレッジ


def fetch_rules(http: HTTP, symbol: str, category: str = "linear") -> SymbolRules:
    res = http.get_instruments_info(category=category, symbol=symbol)
    if res["retCode"] != 0:
        raise RuntimeError(f"get_instruments_info失敗: {res['retCode']} {res['retMsg']}")

    items = res["result"]["list"]
    if not items:
        raise LookupError(f"{symbol} は category={category} に存在しません")
    info = items[0]

    pf = info["priceFilter"]
    lf = info["lotSizeFilter"]
    lev = info.get("leverageFilter", {})

    return SymbolRules(
        symbol=info["symbol"],
        category=category,
        tick_size=Decimal(pf["tickSize"]),
        qty_step=Decimal(lf.get("qtyStep") or lf.get("basePrecision") or "0"),
        min_qty=Decimal(lf.get("minOrderQty") or "0"),
        max_qty=Decimal(lf.get("maxOrderQty") or "0"),
        min_notional=Decimal(lf.get("minNotionalValue") or lf.get("minOrderAmt") or "0"),
        max_leverage=Decimal(lev.get("maxLeverage") or "1"),
    )


def floor_to_step(value: Decimal, step: Decimal) -> Decimal:
    """刻み幅に切り捨てで揃える。数量はこちら(過大発注を防ぐ)。"""
    if step == 0:
        return value
    return (value / step).to_integral_value(rounding=ROUND_DOWN) * step


def round_to_step(value: Decimal, step: Decimal) -> Decimal:
    """刻み幅に四捨五入で揃える。価格はこちら。"""
    if step == 0:
        return value
    return (value / step).to_integral_value(rounding=ROUND_HALF_UP) * step


def prepare_order(rules: SymbolRules, price: Decimal, notional_usd: Decimal
                  ) -> tuple[Decimal, Decimal]:
    """想定金額(USD)から、発注可能な (価格, 数量) を組み立てる。"""
    px = round_to_step(price, rules.tick_size)
    qty = floor_to_step(notional_usd / px, rules.qty_step)

    if qty < rules.min_qty:
        raise ValueError(
            f"数量 {qty} が最小注文数量 {rules.min_qty} を下回ります"
            f"({notional_usd} USD では足りません)"
        )
    if rules.min_notional > 0 and px * qty < rules.min_notional:
        raise ValueError(f"注文金額 {px * qty} が最小 {rules.min_notional} 未満です")
    return px, qty


if __name__ == "__main__":
    c = make_client()
    r = fetch_rules(c.http, "BTCUSDT", "linear")
    print(r)

    # 現在価格の0.5%下に、想定100USDの指値を置く場合の値を作る
    last = Decimal(
        c.http.get_tickers(category="linear", symbol="BTCUSDT")["result"]["list"][0]["lastPrice"]
    )
    px, qty = prepare_order(r, last * Decimal("0.995"), Decimal("100"))
    print(f"発注価格={px}  数量={qty}  想定金額={px * qty:.2f} USD")
数量は「切り捨て」、価格は「四捨五入」

数量を四捨五入すると、意図より大きいポジションを持つ可能性があります。特にレバレッジを掛けている場合、丸め方向の誤りはリスク量の誤りに直結します。数量は常に ROUND_DOWN(切り捨て)、価格は ROUND_HALF_UP を既定にしてください。

また spot と linear では lotSizeFilter のフィールド名が異なります(現物は basePrecision / minOrderAmt)。上のコードは両方を吸収していますが、カテゴリ別の差異は記事03で全面的に整理します。

SDKを使わない|requestsで署名を自作する

pybitは便利ですが、以下のような場面では自分で署名を作れたほうが速いです。

V5の署名ルールはシンプルですが、GETとPOSTで署名対象が違うのがハマりどころです。

メソッド 署名対象文字列
GET timestamp + apiKey + recvWindow + queryString
POST timestamp + apiKey + recvWindow + jsonBodyString

POSTで最も多い失敗は、署名に使ったJSON文字列と実際に送信したJSON文字列が違うケースです。requests の json= 引数を使うと requests 側が独自に直列化するため、自分が json.dumps() した文字列とスペースの有無が変わり、署名が一致しません。必ず data= に同じ文字列を渡してください。

bybit_raw.pyサンプル9
"""bybit_raw.py — pybit非依存のV5最小クライアント(HMAC-SHA256署名)
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

import hashlib
import hmac
import json
import time
from typing import Any
from urllib.parse import urlencode

import requests

BASE_URLS = {
    "mainnet": "https://api.bybit.com",
    "testnet": "https://api-testnet.bybit.com",
    "demo": "https://api-demo.bybit.com",
}


class BybitAPIError(RuntimeError):
    def __init__(self, ret_code: int, ret_msg: str, ext: Any = None):
        super().__init__(f"retCode={ret_code} retMsg={ret_msg}")
        self.ret_code = ret_code
        self.ret_msg = ret_msg
        self.ext = ext


class BybitRaw:
    def __init__(
        self,
        api_key: str = "",
        api_secret: str = "",
        env: str = "testnet",
        recv_window: int = 5000,
        timeout: int = 10,
    ):
        self.api_key = api_key
        self.api_secret = api_secret
        self.base = BASE_URLS[env]
        self.recv_window = recv_window
        self.timeout = timeout
        self.session = requests.Session()
        self.session.headers.update({"Referer": "codetribe"})  # 任意

    # ---- 署名 --------------------------------------------------------
    def _sign(self, timestamp: str, payload: str) -> str:
        """V5署名: timestamp + apiKey + recvWindow + (queryString | jsonBody)"""
        message = f"{timestamp}{self.api_key}{self.recv_window}{payload}"
        return hmac.new(
            self.api_secret.encode("utf-8"),
            message.encode("utf-8"),
            hashlib.sha256,
        ).hexdigest()

    def _auth_headers(self, payload: str) -> dict[str, str]:
        ts = str(int(time.time() * 1000))
        return {
            "X-BAPI-API-KEY": self.api_key,
            "X-BAPI-TIMESTAMP": ts,
            "X-BAPI-RECV-WINDOW": str(self.recv_window),
            "X-BAPI-SIGN": self._sign(ts, payload),
            "X-BAPI-SIGN-TYPE": "2",          # 2 = HMAC-SHA256
            "Content-Type": "application/json",
        }

    # ---- リクエスト --------------------------------------------------
    def get(self, path: str, params: dict | None = None, *, auth: bool = True) -> dict:
        # 署名対象のqueryStringと、実際に送るqueryStringを同一にするため
        # ここで一度だけ文字列化し、それをURLに直接連結する
        query = urlencode(params or {})
        headers = self._auth_headers(query) if auth else {}
        url = f"{self.base}{path}" + (f"?{query}" if query else "")
        r = self.session.get(url, headers=headers, timeout=self.timeout)
        return self._unwrap(r)

    def post(self, path: str, body: dict | None = None) -> dict:
        # 署名した文字列と送信する文字列を完全に一致させる。
        # requestsのjson=は独自に直列化するので使わない(署名不一致の原因)。
        payload = json.dumps(body or {}, separators=(",", ":"))
        headers = self._auth_headers(payload)
        r = self.session.post(
            f"{self.base}{path}", data=payload, headers=headers, timeout=self.timeout
        )
        return self._unwrap(r)

    # ---- レスポンス処理 ----------------------------------------------
    @staticmethod
    def _unwrap(r: requests.Response) -> dict:
        # レート制限の残量はヘッダで返る(記事05で活用)
        limit_status = r.headers.get("X-Bapi-Limit-Status")
        if limit_status is not None and int(limit_status) < 3:
            print(f"[warn] レート残量わずか: {limit_status}")

        if r.status_code == 403:
            raise BybitAPIError(-403, "IP単位のレート制限に到達(約10分の制限)")
        r.raise_for_status()

        data = r.json()
        if data.get("retCode") != 0:
            raise BybitAPIError(data.get("retCode"), data.get("retMsg", ""),
                                data.get("retExtInfo"))
        return data.get("result") or {}


if __name__ == "__main__":
    from config import load_credentials

    cred = load_credentials()
    api = BybitRaw(cred.api_key, cred.api_secret, env=cred.env.value)

    # 1) 公開エンドポイント(認証なし)
    srv = api.get("/v5/market/time", auth=False)
    print("server time:", srv["timeSecond"])

    # 2) 認証付きGET
    wallet = api.get("/v5/account/wallet-balance", {"accountType": "UNIFIED"})
    print("総資産:", wallet["list"][0]["totalEquity"])

    # 3) 認証付きPOST(テストネットでのみ実行してください)
    # order = api.post("/v5/order/create", {
    #     "category": "linear", "symbol": "BTCUSDT", "side": "Buy",
    #     "orderType": "Limit", "qty": "0.001", "price": "50000",
    #     "timeInForce": "PostOnly",
    # })
    # print("orderId:", order["orderId"])

署名エラーが出たときのデバッグ手順

retCode=10004(sign error)は情報が少なく、原因の切り分けが難しいエラーです。署名対象文字列をそのままダンプするのが最短ルートです。

debug_sign.pyサンプル10
"""debug_sign.py — 署名エラー(10004)の切り分けヘルパ
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

import hashlib
import hmac
import json
import time
from urllib.parse import urlencode


def dump_signature(api_key: str, api_secret: str, *,
                   method: str = "GET",
                   params: dict | None = None,
                   recv_window: int = 5000) -> None:
    ts = str(int(time.time() * 1000))

    if method.upper() == "GET":
        payload = urlencode(params or {})
    else:
        payload = json.dumps(params or {}, separators=(",", ":"))

    message = f"{ts}{api_key}{recv_window}{payload}"
    sign = hmac.new(api_secret.encode(), message.encode(), hashlib.sha256).hexdigest()

    print("--- 署名の内訳 -------------------------------------------")
    print(f"timestamp   : {ts}")
    print(f"apiKey      : {api_key[:4]}****  (長さ {len(api_key)})")
    print(f"recvWindow  : {recv_window}")
    print(f"payload     : {payload!r}")
    print(f"署名対象     : {message[:20]}...{message[-40:]!r}")
    print(f"X-BAPI-SIGN : {sign}")
    print("----------------------------------------------------------")
    print("チェック項目:")
    print("  1. payload は実際に送信する文字列と1文字も違わないか")
    print("     (POSTで requests の json= を使っていないか)")
    print("  2. apiKey / apiSecret の前後に改行・空白が混じっていないか")
    print("  3. 接続先ドメインとキーの環境が一致しているか")
    print("     (testnetのキーを api.bybit.com に投げていないか)")
    print("  4. timestamp のズレが recvWindow 以内か(10002ならこれ)")


if __name__ == "__main__":
    from config import load_credentials

    cred = load_credentials()
    dump_signature(cred.api_key, cred.api_secret,
                   method="GET", params={"accountType": "UNIFIED"})
.envのコピペで混入する見えない文字

APIキーをブラウザからコピーする際に、末尾に改行や全角スペースが混入して10004になるケースが非常に多いです。config.py で .strip() を掛けているのはこのためです。それでも直らない場合は上の len(api_key) を確認してください。

RSA署名の実装、非同期クライアント、オフセット補正付きタイムスタンプなどは記事02で詳しく扱います。

V5レスポンス構造とretCodeの読み方

V5のすべてのエンドポイントは、同じ封筒(エンベロープ)で結果を返します。

V5共通レスポンス構造JSON
{
  "retCode": 0,                  // 0 が成功。それ以外はすべてエラー
  "retMsg": "OK",                // エラーメッセージ
  "result": { ... },             // 実データ。多くは {"list": [...], "nextPageCursor": "..."}
  "retExtInfo": {},              // バッチ処理時の個別結果などが入る
  "time": 1785000000000          // サーバー時刻(ms)
}
HTTP 200 でもエラーのことがある

V5は業務エラーをHTTPステータス200+retCode≠0で返します。requests の raise_for_status() だけでは検知できません。必ず retCode を確認するラッパを通してください。pybitも retCode≠0 を例外にせず辞書で返す場合があるため、自分で retCode を見るコードを1箇所に集約するのが安全です。

unwrap.pyサンプル11
"""unwrap.py — retCodeを1箇所で処理するラッパ
本コードは本人利用に限り自由に使用可。再配布・商用利用・販売は禁止。
"""
from __future__ import annotations

from typing import Any


class BybitAPIError(RuntimeError):
    def __init__(self, ret_code: int, ret_msg: str, ext: Any = None):
        super().__init__(f"retCode={ret_code} retMsg={ret_msg}")
        self.ret_code = ret_code
        self.ret_msg = ret_msg
        self.ext = ext

    @property
    def retryable(self) -> bool:
        # レート制限・サーバー内部エラーは時間を置けば通る可能性がある
        return self.ret_code in {10006, 10016}

    @property
    def needs_reconcile(self) -> bool:
        # 「注文が見つからない」系は、送れているのに結果を取り違えている
        # 可能性があるため、取引所側の状態照会が必要(記事17)
        return self.ret_code in {110001, 110004}


# エラーだが実質成功として扱ってよいコード
BENIGN_CODES = {
    110043,   # レバレッジ変更なし(既に同じ値が設定されている)
}


def unwrap(res: dict) -> dict:
    """V5レスポンスからresultを取り出す。retCode≠0なら例外にする。"""
    code = res.get("retCode")
    if code == 0:
        return res.get("result") or {}
    if code in BENIGN_CODES:
        return res.get("result") or {}
    raise BybitAPIError(code, res.get("retMsg", ""), res.get("retExtInfo"))


# 使用例
if __name__ == "__main__":
    from client import make_client

    c = make_client()
    try:
        result = unwrap(c.http.get_wallet_balance(accountType="UNIFIED"))
        print(result["list"][0]["totalEquity"])
    except BybitAPIError as e:
        print(f"APIエラー: {e}  リトライ可={e.retryable}")

ページネーションの共通パターン

履歴系のエンドポイントは result.nextPageCursor でページを繰ります。これも1箇所に共通化しておくと、以降の記事のコードがすべて短くなります。

paginate.py(抜粋)共通処理
from collections.abc import Callable, Iterator


def paginate(fetch: Callable[..., dict], *, limit: int = 200,
             max_pages: int = 100, **kwargs) -> Iterator[dict]:
    """cursorベースのV5エンドポイントを全件たどる。

    使用例:
        for row in paginate(c.http.get_executions,
                            category="linear", symbol="BTCUSDT"):
            print(row["execTime"], row["execPrice"])
    """
    cursor = None
    for _ in range(max_pages):
        params = dict(kwargs, limit=limit)
        if cursor:
            params["cursor"] = cursor
        result = unwrap(fetch(**params))

        rows = result.get("list") or []
        yield from rows

        cursor = result.get("nextPageCursor")
        if not cursor or not rows:
            return

よくあるエラーと対処

retCode 意味 実際の原因と対処 リトライ
10001 パラメータ不正 category の指定漏れ、シンボル名の大文字小文字、accountType の誤り、数値を数値型で送っている(V5は文字列で渡す) 不可
10002 タイムスタンプ範囲外 ローカル時計のズレが recv_window を超過。NTP同期(w32tm /resync / chronyc makestep)。サンプル5で計測 同期後に可
10003 APIキー不正 環境とキーの不一致(testnetキーを本番に送信)、キーの有効期限切れ、IP制限に引っかかっている 不可
10004 署名エラー 署名対象文字列と送信内容の不一致(POSTのJSON直列化)、Secretに改行混入。サンプル10でダンプ 不可
10005 権限不足 Read-Onlyキーで発注しようとしている。該当権限を持つキーに差し替える 不可
10006 レート制限超過 UID×エンドポイント単位の秒間上限を超過。指数バックオフ+トークンバケット(記事05) 可
10016 サーバー内部エラー Bybit側の一時的障害。発注系では危険。注文が通っている可能性があるので状態照会してから再送(記事17) 照会後
110007 残高不足 利用可能証拠金(totalAvailableBalance)を超える発注。既存の未約定注文が証拠金を拘束していないか確認 不可
110043 レバレッジ変更なし すでに同じレバレッジが設定されている。実質成功なので無視してよい(記事21) 無視
HTTP 403 IP単位のレート制限 5秒あたり600リクエストの上限を超過。約10分の制限がかかる。並列数を絞る(記事05) 10分後

retCodeの一覧は公式のError Codesページが正典です。上表は「bot実装で実際に踏むもの」に絞っています。網羅的な逆引きと自動リカバリの実装は記事06で扱います。

実運用に進む前に必ず押さえる5つのこと

ここまでで「データを取る」「残高を見る」ができました。しかし発注を伴う本番運用に進むには、あと5つの壁があります。それぞれ専用記事で扱いますが、全体像を先に示しておきます。

最初の1週間の進め方(推奨)

1日目:本記事のサンプル1〜8をtestnetで動かす。
2〜3日目:記事07でローカルにOHLCVを蓄積する(データが手元にないと何も検証できません)。
4〜5日目:記事13でtestnetに最小ロットの指値・成行を出し、記事18で自分の約定履歴を集計する。
6〜7日目:記事31でバックテスト基盤を作る。戦略に手を付けるのはここから。

順番を逆にして「まず勝てるロジックを探す」から入ると、検証環境がないため何が良いのか判断できず、最終的に他人のパラメータを写すだけになります。

参考リンク(一次情報)

よくある疑問Q&A

pybitとccxt、どちらを使うべきですか?
複数取引所に同じコードで対応したいならccxt、Bybitに絞って細かい機能を使い切りたいならpybitまたは自作クライアントです。V5固有のパラメータ(tpslMode、positionIdx、orderFilter、slippageTolerance など)はccxtの共通インターフェースからは扱いにくく、結局 params に生の辞書を渡す形になるため、抽象化の利点が薄れます。本シリーズはBybit専用の前提でpybit+自作クライアントを併用します。
APIキーの権限を後から変更できますか?
既存キーの権限・IP制限は編集できます。ただしSecretは再表示されませんので、紛失した場合は新しいキーを発行してください。運用中のbotのキーを差し替える際は、新キーを発行→.envを更新→bot再起動→旧キー削除の順に行うと無停止に近い形で交代できます。
testnetで動いたのに本番で認証エラーになります
testnetとmainnetは完全に別のアカウント・別のキーです。testnetのキーは api.bybit.com では使えません(retCode 10003)。また本番キーにIP制限を掛けている場合、実行環境のグローバルIPが登録済みか確認してください。加えて、所属エンティティによって接続先ドメインが異なる場合があります(日本国内向けの api.manepa.jp など)。
レスポンスの数値がすべて文字列なのはなぜですか?
浮動小数点による精度劣化を避けるためです。金融APIでは一般的な設計で、Bybitに限りません。受け取った側でfloat()すると誤差が入るため、価格・数量はDecimalで扱い、統計計算に入る直前でだけfloatにするのが正しい扱い方です。サンプル8の丸め関数がこの前提で書かれています。
botはWindowsでも動きますか?
開発・検証はWindowsで問題ありません。ただし24時間の本番稼働はLinux VPSを推奨します。理由は、Windows Updateによる強制再起動、プロセス管理の仕組み(systemdに相当するものがない)、そしてBybitのサーバーに近いリージョンのLinux VPSが安価に選べる点です。Docker化しておけば開発環境と本番環境の差異も小さくできます(記事38)。
最小いくらから自動売買を試せますか?
まずtestnetとデモトレードで資金を入れずに検証してください。本番に移す段階でも、最初は「最小ロット×1銘柄」で数週間動かし、ログ・約定履歴・想定と実際の乖離を確認するのが順序です。銘柄ごとの最小注文数量・最小注文金額はサンプル8の fetch_rules() で取得できます。金額を増やすのは、記事18の執行品質の集計と記事32の過剰最適化検証を通過してからにしてください。
Jupyter Notebookで開発してもよいですか?
データ分析・バックテストには最適ですが、発注権限のあるキーをNotebookに読み込ませるのは避けてください。セルの再実行で意図せず発注してしまう事故が起きます。分析用にはRead-Onlyキーを使い、発注は別プロセス(スクリプト)から行う分離を最初から徹底することを勧めます。
V5より前のAPI(V3など)のコードは動きますか?
旧バージョンのエンドポイントは段階的に廃止されています。ネット上に残っている古いサンプルコード(/v2/private/order/create や /spot/v3/... など)はそのままでは動かないと考えてください。V5の /v5/... パスであることを確認するのが、記事やコードを参考にする際の第一のフィルタになります。

注意事項・免責事項

投資は自己判断・自己責任でお願いいたします。本ブログの情報・ツール・ソフトウェアを参考・使用して、取引をされて何らかの損失を被られても、当サイトでは責任は一切負いません(間接的・付随的な障害・損失も含め一切の責任を負いません)。自己責任でご利用ください。

当サイトからダウンロードしたプログラム・EAは本人利用に限り完全無料でご利用いただけます。プログラムの全てまたは一部の複製・コピー・リバースエンジニアリング・改変・2次配布・商用利用・転売・販売等は一切禁止いたします。違反を発見した場合は法的処置を行います。

当サイト上に存在するソフトウェア・ツール・文章・画像・動画等の著作物を無断転載することを禁止します。引用の範囲を超えるものについては、法的処置を行います。

当サイトで配布するツール・ソフトウェアは無料提供ですのでサポートなどは行っておりません(逆に丁寧にサポートしているサイトはほとんど違法サイトですのでご注意ください。投資助言・代理業登録なしでサポート・助言することは法律で禁止されています)。万が一、ツールやソフトウェアに不具合や問題があっても当サイトでは修正・対応などができない場合があります。ご利用の環境でトラブルが発生しても当サイトでは助言することはできませんので自己責任でご利用ください。検索するなどして自分で解決してください。

当サイトでは取引所・証券会社へのリンクを貼っていますが、これは情報として提供するものであり、勧誘行為などは一切行っておりません。そのため、取引所・証券会社の登録方法・使い方・オススメ金融機関・オススメ金融商品などを説明した記事はサイト内にありませんので、ご自身で調べた上で判断ください(本当はサイト内で丁寧に説明したいのですが、仲介・取次ぎにあたる可能性があり第一種金融商品取引業登録を行っていない場合、違法となる可能性があるため出来ません。ご容赦ください)。

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。当サイト掲載情報やリンク先の掲載情報の合法性、正確性、道徳性、最新性、適切性、著作権の許諾や有無など、その内容については一切の保証を致しかねます。

当サイトは、ご訪問いただいた時間、訪問者のアクセス元のホスト名、IPアドレス、OSとブラウザのバージョン、リンク元のURL、モニターの情報等のパソコン環境情報を収集し、アクセス解析をしております。この目的は訪問者が検索サイトからご訪問いただいた場合、どのような検索で当サイトに来訪いただいたかの解析にのみ使用しており、第3者に公開はいたしません。また、個人を特定するものではありません。